问题 运行使用XMLHttpRequest下载的JavaScript


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

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

谢谢你的帮助


4351
2017-09-16 16:42


起源



答案:


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

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();
}

或类似的东西。

但是,要小心这种方法。它很容易受到跨站脚本攻击,这可能会让您(以及您的用户)面临各种各样的肮脏行为。你需要采取适当的预防措施。


8
2017-09-16 16:48



发布时没有看到您的评论。你完全正确。但是我认为你必须在onreadystatechange处理程序中检查readyState值,就像这里显示的那样 w3schools.com/ajax/ajax_xmlhttprequest_onreadystatechange.asp。 - Kirill Muzykov
@Insomniac:Duly注意到,谢谢。发布固定!如果流现在在声明中间结束将不会很好,是吗? - Mike Hofer
我很确定你仍然需要将你的条件改为if(xmlhttp.status == 200 && xmlhttp.readyState == 4) - Kirill Muzykov
甚至更好地使用这样的东西 plugins.jquery.com/project/rloader  避免评估。 - Kirill Muzykov
虽然我喜欢jquery,但就个人而言,它并不适合所有环境。如果我在工作中将它介绍到产品中,我个人会把嘴唇钉在墙上。所以,你向人们展示这两种方法,并享受增加知识的好处。 - Mike Hofer


答案:


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

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();
}

或类似的东西。

但是,要小心这种方法。它很容易受到跨站脚本攻击,这可能会让您(以及您的用户)面临各种各样的肮脏行为。你需要采取适当的预防措施。


8
2017-09-16 16:48



发布时没有看到您的评论。你完全正确。但是我认为你必须在onreadystatechange处理程序中检查readyState值,就像这里显示的那样 w3schools.com/ajax/ajax_xmlhttprequest_onreadystatechange.asp。 - Kirill Muzykov
@Insomniac:Duly注意到,谢谢。发布固定!如果流现在在声明中间结束将不会很好,是吗? - Mike Hofer
我很确定你仍然需要将你的条件改为if(xmlhttp.status == 200 && xmlhttp.readyState == 4) - Kirill Muzykov
甚至更好地使用这样的东西 plugins.jquery.com/project/rloader  避免评估。 - Kirill Muzykov
虽然我喜欢jquery,但就个人而言,它并不适合所有环境。如果我在工作中将它介绍到产品中,我个人会把嘴唇钉在墙上。所以,你向人们展示这两种方法,并享受增加知识的好处。 - Mike Hofer


您可以使用以字符串形式运行脚本

eval()

不过我建议你添加新的

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

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


5
2017-09-16 16:51



eval来自XHR的危险比注射一样少 <script> 由于同源政策放在XHR上(不存在 <script>)。但是,设置 <script> 通常更简单。 - strager
我完全同意这两种方法都存在安全问题,但是如果你想要动态脚本加载你没有太多可供选择:)而且eval()'ed脚本不会被缓存,如果你有一个很大的话会严重影响性能脚本。 - Kirill Muzykov


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

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

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();

3
2017-07-07 17:10





我在移动网络项目上遇到了挑战,神奇的是设置了“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();

0
2018-02-06 22:07





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


-1
2017-09-16 16:50





您将使用eval(param),参数将是请求的响应。您请求JavaScript的方法很荒谬,因为它只会延迟代码运行。只需使用功能和事件。


-1
2017-09-16 17:50