通过AJAX返回执行JavaScript的正确方法(没有jQuery)

时间:2011-11-11 17:14:48

标签: javascript ajax eval

假设我收到了对JavaScript和HTML混合的AJAX数据加载请求的响应,例如:

<script>window.alert('Hello World!');</script>
<p>This is a paragraph. Lorem ipsum dolor sit amet...</p>

如果我只是将该响应放入div或其他容器中,则脚本不会自动执行。我知道这可以通过eval()函数完成(如下例所示),但是eval是邪恶的,所以我该如何正确地做到这一点? 注意:我没有使用jQuery。

以下是AJAX加载程序的示例

function Load(id,url){
    var ajax=new XMLHttpRequest();
    ajax.onreadystatechange=function(){
        if(ajax.readyState!=4)return;
        var obj=document.getElementById(id);
        if(!obj)return;
        obj.innerHTML=ajax.responseText;

        // load any scripts
        var s=obj.getElementsByTagName('script');
        for(var i=0;i<s.length;++i)window.eval(s[i].innerHTML); // <-- bad
    }
    ajax.open("GET",url,true);
    ajax.send(null);
}

3 个答案:

答案 0 :(得分:3)

请注意,您正在接收用户的输入并在您网站上的脚本环境中运行。因此,脚本可以执行浏览器/域上运行的JavaScript能够执行的任何操作(包括cookie窃取,XSS,偷渡式恶意软件等)。

您唯一可以现实地做的是减轻风险,而不是eval()用户提供的内容。我建议考虑以下替代方案:

  1. 使用iframe作为运行用户脚本的环境: http://dean.edwards.name/weblog/2006/11/sandbox/
  2. 使用Caja。它允许网站安全地嵌入来自第三方的DHTML Web应用程序,并实现嵌入页面和嵌入式应用程序之间的丰富交互。它使用对象功能安全模型来实现各种灵活的安全策略。 http://code.google.com/p/google-caja/

答案 1 :(得分:2)

在这种情况下,eval并不是特别邪恶,它与动态添加一个下拉.js文件并运行它的脚本标记有很大的不同。也就是说,还有其他选项,例如,您可以动态创建脚本标记,使用您下拉的脚本标记的内容创建文本节点,然后将其添加到文档中。与innerHTML技术不同,它实际上将运行内容。实际上,优于eval的唯一优势是,如果崩溃或语法错误,您可能会获得更有意义的堆栈跟踪等。

var newScriptTag = document.createElement('script');
newScriptTag.appendChild(document.createTextNode(
     origScriptTag.innerHTML)
document.body.appendChild(newScriptTag);

答案 2 :(得分:0)

我今天通过将JavaScript放在响应HTML的底部来解决这个问题。

我有一个AJAX请求返回了一堆显示在叠加层中的HTML。我需要将单击事件附加到返回的响应HTML / overlay中的按钮。在普通页面上,我将JavaScript包装在“window.onload”或“$(document).ready”中,以便在渲染新叠加层的DOM之后将事件处理程序附加到DOM对象,但是因为这是一个AJAX响应,而不是一个新的页面加载,该事件从未发生过,浏览器从未执行过我的JavaScript,我的事件处理程序从未附加到DOM元素,而我的新功能不起作用。再一次,我通过不在文档的头部使用“$(document).ready”来解决我的“在AJAX响应问题中执行JavaScript”,而是将我的JavaScript放在文档的末尾并让它在HTML之后运行/ DOM已经渲染。