如何获取指定为<script>标记的'src'的文件的内容?


67

如果我有这样的脚本标签:

<script
    id = "myscript"
    src = "http://www.example.com/script.js"
    type = "text/javascript">
</script>

我想获取“ script.js”文件的内容。我正在考虑类似的东西,document.getElementById("myscript").text但在这种情况下不起作用。


我很难弄清楚为什么您需要访问内容?您能否提供一些有关您打算如何处理的信息?
基因

您将在哪里缓存它?我的意思是,您如何才能使缓存的数据在页面加载的脚本的生存期之后继续存在?
SpoonMeiser

马库斯:我建议您对问题进行澄清,否则您将继续获得与以下内容相同的答案:)
Lasar

1
通过调用为我存储此值的javascript函数。但这实际上不在这个问题的范围内。
Markus Johansson,

7
这个问题已有几年历史了。但是,我只想在现代用法上投入2美分。客户端模板的使用正在增长,并且在javascript之外定义模板的方法通常是将模板嵌入<script>标记(John Resig Microtemplating)中以避免转义。但是,这意味着模板不会被缓存,并且必须与辅助内容一起呈现。一种解决方法是将模板放在单独的文件中,并使用“ script”标签链接到它,但是如果没有AJAX,就无法获取文件的内容。
Daryl Teo 2012年

Answers:


10

您要获取文件http://www.example.com/script.js的内容吗?如果是这样,您可以使用AJAX方法来获取其内容,前提是该内容与页面本身位于同一服务器上。

您能详细说明您要完成的工作吗?


2
我想存储脚本的内容,以便可以缓存它并稍后再直接使用它,而不必从外部Web服务器(而不是与页面位于同一服务器上)中获取它。
Markus Johansson,

9
如果是这样,请不必担心,浏览器会自行处理外部JS脚本的缓存。
gizmo

1
@Gizmo那么Google为什么要在本地存储中缓存脚本?浏览器缓存不可靠。
Qix-蒙尼卡(Monica)

3
@Qix浏览器缓存是可靠的,但通常需要往返服务器(例如:检查ETag)。使用本地存储可以防止这种往返。
gizmo 2014年

9

tl; dr脚本标签不受CORS同源策略的约束,因此javascript / DOM无法提供对通过<script>标签加载的资源的文本内容的访问,否则它会中断same-origin-policy

长版本: 大多数其他答案(以及公认的答案)均正确表明,“正确”方式(用于获取通过<script>加载到页面中的javascript文件的文本内容)正在使用XMLHttpRequest来执行另一个单独的附加请求scriptssrc属性中指示的资源,以下简短的javascript代码将演示这些内容。但是,我发现其他答案并未解决获取javascript文件文本内容的问题,即允许访问通过包含的文件内容<script src=[url]></script>会破坏CORS策略,例如,现代浏览器会阻止XHR资源提供访问控制允许来源标头,因此浏览器除受限制之外CORS,不允许其他任何方式获取内容。

使用以下代码(如在其他问题“使用XHR / AJAX”中提到的那样),可以对文档中所有非内嵌脚本标签发出另一个请求。

function printScriptTextContent(script)
{
  var xhr = new XMLHttpRequest();
  xhr.open("GET",script.src)
  xhr.onreadystatechange = function () {
    if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
      console.log("the script text content is",xhr.responseText);
    }
  };
  xhr.send();
}
Array.prototype.slice.call(document.querySelectorAll("script[src]")).forEach(printScriptTextContent);

因此,我将不再重复,而是想通过此答案在方面说明为什么


谢谢-这是解释了唯一的答案,为什么必须使用AJAX来检索往返到服务器的文本,为什么这是已经通过脚本标签加载是不可另外地。
sdbbs

9

更新:现在不建议使用HTML导入(替代)。

---

我知道已经有点晚了,但是某些浏览器支持标记LINKrel="import"属性。

http://www.html5rocks.com/zh-CN/tutorials/webcomponents/imports/

<link rel="import" href="/path/to/imports/stuff.html">

对于其余部分,ajax仍然是首选方式。


我之所以寻求此解决方案,部分原因是因为我没有使用Web服务器来提供页面(直接从文件系统在本地获取页面),并且我认为您不能使用不带Web服务器的xmlhttprequest。
Jose_X

@Jose_X:您可以使用浏览器标志绕过该限制。我认为对于Chrome浏览器来说,启动浏览器时它就像“ --allow-file-access-from-files”。可能会有chrome:// flags(onextrapixel.com/2014/09/01/…
Sauleil

2
现在该接口已过时。
拥抱

5

我认为内容不会通过DOM提供。您可以获取src属性的值,并使用AJAX从服务器请求文件。


0

.text确实为您提供了标签的内容,只是您的open标签和end标签之间什么都没有。您可以使用.src来获取元素的src属性,然后如果要获取javascript文件,则可以点击该链接并对其进行ajax请求。


0

在评论我以前的答案时:

我想存储脚本的内容,以便可以缓存它并稍后再直接使用它,而不必从外部Web服务器(而不是与该页面位于同一服务器上)中获取它。

在这种情况下,最好使用服务器端脚本来获取和缓存脚本文件。根据您的服务器设置,您可以只获取文件(如果希望更改,可以定期通过cron进行获取),也可以使用所选语言用小的脚本执行类似的操作。



0

是的,就像公认的答案一样,Ajax是做到这一点的方法。如果您不了解细节,则有很多陷阱。如果使用jQuery.load(...),则假定错误的内容类型(用html代替应用程序/ javascript),这可能会由于将不需要的内容<br>放入(scriptNode).innerText等内容而变得混乱。然后,如果使用jQuery.getScript(...),则下载的脚本将立即执行,而这可能不是您想要的(如果有多个文件,则可能会弄乱文件的加载顺序)。

我发现最好jQuery.ajaxdataType: "text"

我在具有框架集的项目中使用了这种Ajax技术,其中框架集和/或多个框架需要相同的JavaScript,以避免服务器多次发送该JavaScript。

这是经过测试且可以正常工作的代码:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
<html>
    <head>
        <script id="scriptData">
            var scriptData = [
                { name: "foo"    , url: "path/to/foo"    },
                { name: "bar"    , url: "path/to/bar"    }
            ];
        </script>
        <script id="scriptLoader">
            var LOADER = {
                loadedCount: 0,
                toBeLoadedCount: 0,
                load_jQuery: function (){
                    var jqNode = document.createElement("script");
                    jqNode.setAttribute("src", "/path/to/jquery");
                    jqNode.setAttribute("onload", "LOADER.loadScripts();");
                    jqNode.setAttribute("id", "jquery");
                    document.head.appendChild(jqNode);
                },
                loadScripts: function (){
                    var scriptDataLookup = this.scriptDataLookup = {};
                    var scriptNodes = this.scriptNodes = {};
                    var scriptNodesArr = this.scriptNodesArr = [];
                    for (var j=0; j<scriptData.length; j++){
                        var theEntry = scriptData[j];
                        scriptDataLookup[theEntry.name] = theEntry;
                    }
                    //console.log(JSON.stringify(scriptDataLookup, null, 4));
                    for (var i=0; i<scriptData.length; i++){
                        var entry = scriptData[i];
                        var name = entry.name;
                        var theURL = entry.url;
                        this.toBeLoadedCount++;
                        var node = document.createElement("script");
                        node.setAttribute("id", name);
                        scriptNodes[name] = node;
                        scriptNodesArr.push(node);
                        jQuery.ajax({
                            method   : "GET",
                            url      : theURL,
                            dataType : "text"
                        }).done(this.makeHandler(name, node)).fail(this.makeFailHandler(name, node));
                    }
                },
                makeFailHandler: function(name, node){
                    var THIS = this;
                    return function(xhr, errorName, errorMessage){
                        console.log(name, "FAIL");
                        console.log(xhr);
                        console.log(errorName);
                        console.log(errorMessage);
                        debugger;
                    }
                },
                makeHandler: function(name, node){
                    var THIS = this;
                    return function (fileContents, status, xhr){
                        THIS.loadedCount++;
                        //console.log("loaded", name, "content length", fileContents.length, "status", status);
                        //console.log("loaded:", THIS.loadedCount, "/", THIS.toBeLoadedCount);
                        THIS.scriptDataLookup[name].fileContents = fileContents;
                        if (THIS.loadedCount >= THIS.toBeLoadedCount){
                            THIS.allScriptsLoaded();
                        }
                    }
                },
                allScriptsLoaded: function(){
                    for (var i=0; i<this.scriptNodesArr.length; i++){
                        var scriptNode = this.scriptNodesArr[i];
                        var name = scriptNode.id;
                        var data = this.scriptDataLookup[name];
                        var fileContents = data.fileContents;
                        var textNode = document.createTextNode(fileContents);
                        scriptNode.appendChild(textNode);
                        document.head.appendChild(scriptNode); // execution is here
                        //console.log(scriptNode);
                    }
                    // call code to make the frames here
                }
            };
        </script>
    </head>
    <frameset rows="200pixels,*" onload="LOADER.load_jQuery();">
        <frame src="about:blank"></frame>
        <frame src="about:blank"></frame>
    </frameset>
</html>

相关问题


-1

如果您要访问<script>标记的属性而不是script.js的内容,请使用XPath可能就是您想要的。

它将允许您获取每个脚本属性。

如果您要查找的是example.js文件的内容,则可以触发AJAX请求以获取该文件。


-2

使用2008年风格的DOM绑定,它宁愿是:

document.getElementById('myscript').getAttribute("src");
document.getElementById('myscript').getAttribute("type");

这与问题无关
RecursiveExceptionException

-2

您想使用innerHTML属性获取脚本标签的内容:

document.getElementById("myscript").innerHTML

但是正如@olle在另一个答案中所说,您可能希望阅读以下内容:http ://ejohn.org/blog/degrading-script-tags/


-2

如果提供了src属性,则要求用户代理忽略该元素的内容,如果您需要从外部脚本访问该元素,则可能是做错了什么。

更新:我看到您已经添加了注释,以表示想要缓存该脚本并在以后使用它。为了什么目的 假设HTTP是缓存友好的,那么浏览器可能已经满足了缓存需求。


2
这是一个场景。页面正在使用jsonp添加内容。我希望扩展程序可以使用该内容来添加更多信息。现在,当我监视DOMSubtreeModified时,我可以跟踪jsonp添加事件,但是我无法访问源(该源仅包含带有json的函数调用)。
Andrius Bentkus 2014年

@AndriusBentkus —如果您有一个新问题,请提出一个新问题
昆汀

2
我有完全相同的问题,我只是给了您一个场景,他的问题很有意义。
Andrius Bentkus 2014年

-3

我建议这个问题的答案是使用DOM元素的“ innerHTML”属性。当然,如果脚本加载,你就不会需要做一个Ajax调用得到它。

因此Sugendran应该是正确的(不确定为什么他被否决而没有解释)。

var scriptContent = document.getElementById("myscript").innerHTML;

如果脚本元素为:script元素的innerHTML属性应为您提供字符串形式的脚本内容:

  • 内联脚本,或
  • 脚本已加载(如果使用src属性)

olle也给出了答案,但是我认为它被他的建议“糊涂”了,因为他建议首先通过ajax加载它,我认为他的意思是“内联”而不是两者之间。

如果您要在其中放置js,则可以通过innerHTML访问它。


关于此技术的有用性:

在获取“未定义的变量”(我的脚本(例如,来自工具栏或扩展程序的注入错误的脚本)中未包含)后,我一直希望将这种技术用于(JavaScript异常的)客户端错误日志记录-因此我不认为这是一个出路的想法。


4
在Firefox v.24中对此进行了尝试-不适用于外部脚本。
mas.morozov 2013年

6
这是行不通的-您获得脚本标签本身的内容,而不是外部脚本的内容。
大卫

-5

不确定为什么需要这样做?

另一种方法是将脚本保存在某个位置的隐藏元素中,然后使用Eval运行它。然后,您可以查询对象的innerHtml属性。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.