运行使用 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 注入比注入 <script>
更危险,因为 XHR 上设置了同源策略(<script>
不存在)。但是,设置<script>
通常更简单。
我完全同意这两种方法都存在安全问题,但是如果您想要动态脚本加载,您没有太多选择:) 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 下载文件中的 javascript? [复制]
使用 new XMLHttpRequest() 制作下载文件进度条