运行使用 XMLHttpRequest 下载的 JavaScript

Posted

技术标签:

【中文标题】运行使用 XMLHttpRequest 下载的 JavaScript【英文标题】:Running JavaScript downloaded with XMLHttpRequest 【发布时间】:2011-04-13 07:54:38 【问题描述】:

我有一个网站,当用户单击链接时,它使用 XMLHttpRequest 加载信息。系统运行良好,但我希望能够执行在此过程中收集的 javascript

这是一个问题,因为我想“按需”下载脚本,而不是在页面加载时全部加载。

感谢您的帮助

【问题讨论】:

【参考方案1】:

我相信推荐的解决方案是这样的:

function include(scriptUrl)

    var xmlhttp = new XMLHttpRequest();
    xmlhttp.open("GET", scriptUrl);
    xmlhttp.onreadystatechange = function()
    
        if ((xmlhttp.status == 200) && (xmlhttp.readyState == 4))
        
            eval(xmlhttp.responseText);
        
    ;
    xmlhttp.send();

或者类似的东西。

但是,请注意这种方法。它很容易受到跨站点脚本的攻击,这可能会使您(和您的用户)面临各种讨厌的事情。您需要采取适当的预防措施。

【讨论】:

发布时没有看到您的评论。你完全正确。但是我认为您必须检查 onreadystatechange 处理程序中的 readyState 值,就像这里显示的 w3schools.com/ajax/ajax_xmlhttprequest_onreadystatechange.asp. @Insomniac:注意到了,谢谢。帖子固定!如果流现在在语句的中间结束,就不会很好地工作,不是吗? 我很确定您仍然需要将条件更改为 if (xmlhttp.status == 200 && xmlhttp.readyState == 4) 最好使用plugins.jquery.com/project/rloader 这样的东西来避免评估。 虽然我个人喜欢 jquery,但它并不适合所有环境。如果我在工作中将它引入产品中,我个人会将嘴唇钉在墙上。因此,您向人们展示了这两种方法,并享受增加知识带来的好处。【参考方案2】:

最近我找到了答案(它在 Chrome 中有效,在其他浏览器中未经过测试)。

您可以创建dataURL字符串并将其放入script元素的src属性中。

var xhr = XMLHttpRequest(),
    doc = document;
xhr.open('GET', pathToJSFile, true);
xhr.onload = function () 

    var script = doc.createElement('script'),
        base64 = 'data:application/javascript;base64,';
    try 
        base64 += btoa(data.responseText);
     catch (e) 
        // script file may contain characters that not included in Latin1
        var symbols = data.responseText.split('');
        for (var i = 0, l = symbols.length; i < l; i++) 
            var symbol = symbols[i];
            // here we are trying to find these symbols in catch branch
            try 
                btoa(symbol);
             catch (e) 
                var code = symbol.charCodeAt(0).toString(16);
                while (code.length < 4) 
                    code = '0' + code;
                
                // replace original symbol to unicode character
                symbols[i] = '\\u' + code;
            
        
        // create new base64 string from string with replaced characters
        base64 += btoa(symbols.join(''));
     finally 
        script.src = base64;
        // run script
        doc.body.appendChild(script);
    

;
xhr.send();

您可以订阅 xhr.onprogress 以显示进度条。

更新。您可以将脚本文件下载为 blob,然后创建 blob-url。

var xhr = XMLHttpRequest(),
    doc = document;
xhr.responseType = 'blob';
xhr.open('GET', pathToJSFile, true);
xhr.onload = function () 

    var script = doc.createElement('script'),
        src = URL.createObjectURL(xhr.response);

    script.src = src;
    doc.body.appendChild(script);
;
xhr.send();

【讨论】:

但是如果您选择这种插入脚本的方式,通过 createElement('script') 并设置 'src' 属性,为什么不直接通过 'src' 加载脚本呢?此处无需使用 XMLHttpRequest。【参考方案3】:

您可以使用

运行以字符串形式下载的脚本
eval()

不过我建议你添加新的

<script src='..'></script>

到您的文档并有一个回调,它将在下载时调用。有很多 utils 和 jquery 插件。

【讨论】:

eval' 从 XHR 注入比注入 &lt;script&gt; 更危险,因为 XHR 上设置了同源策略(&lt;script&gt; 不存在)。但是,设置&lt;script&gt; 通常更简单。 我完全同意这两种方法都存在安全问题,但是如果您想要动态脚本加载,您没有太多选择:) eval() 的脚本也不会被缓存并且可以如果您的脚本很大,则会严重影响性能。【参考方案4】:

我在一个移动网络项目上遇到了挑战,神奇的是设置“overrideMimeType”。 这已经过验证,可以在 android 4.1 到 Android 6.0 上运行。

var head = document.getElementsByTagName('head');
var injectedScript = document.createElement('script');
head[0].appendChild(injectedScript);

var myRequest = new XMLHttpRequest();
myRequest.onreadystatechange = function() 
  if (myRequest.readyState == 4 && myRequest.status == 200) 
        injectedScript.innerhtml = myRequest.responseText;
    //run a function in the script to load it   
  
;

function start()
    myRequest.open('GET', 'javascript-url-to-download', true);
    myRequest.overrideMimeType('application/javascript');
    myRequest.send();


start();

【讨论】:

【参考方案5】:

您需要使用 eval 来解析 XHR 中的 javascript,请注意,如果您对 javascript 的来源没有绝对信任,这将非常危险。

【讨论】:

这只是一个社会潮流的自动评论:根据信念使用“非常”和“绝对”两个词,没有任何解释。对于原教旨主义编码人员,我建议将 eval is evil 戒律替换为较少询问您不应解析用户输入。遵守这一点,从安全的角度来看,从文本中解析脚本就像添加具有同源策略的脚本一样。

以上是关于运行使用 XMLHttpRequest 下载的 JavaScript的主要内容,如果未能解决你的问题,请参考以下文章

在用户脚本中使用 XMLHttpRequest 下载图像

如何处理 XMLHttpRequest 下载文件中的 javascript? [复制]

使用 new XMLHttpRequest() 制作下载文件进度条

如何解决 Flutter 上的 XMLHttpRequest 错误?

STM32开发板使用J-Link下载后如何让程序自动运行

XMLHttpRequest的折旧替代方案是什么,用于文件保存程序?