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

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

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

感谢您的帮助

【问题讨论】:

    标签: javascript html ajax scripting download


    【解决方案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 戒律替换为较少询问您不应解析用户输入。遵守这一点,从安全的角度来看,从文本中解析脚本就像添加具有同源策略的脚本一样。
      猜你喜欢
      • 1970-01-01
      • 2011-10-02
      • 1970-01-01
      • 2014-05-08
      • 1970-01-01
      • 1970-01-01
      • 2015-07-20
      • 1970-01-01
      • 2017-04-13
      相关资源
      最近更新 更多