为什么脚本不执行?

时间:2018-07-18 01:17:02

标签: javascript html ajax single-page-application

我正在尝试制作一个Web应用程序,以使用AJAX刷新其内容,样式和脚本,因此该网站无需更新页面即可更新所有内容。

所以发生的事情是,我首先获取页面,并且在加载页面时,我使用ajax向服务器发出请求并获取html内容,然后再次请求获取样式,最后再次请求获取脚本并将其放在脚本标签中

<script> //The script goes here </script>

然后,我将script标签放在html内容的末尾,并用内容完全更新正文

<body>
  The HTML content goes here
  <script> //and here is the script </script>
</body>

请求成功并且内容加载,因此样式以及使用浏览器检查器工具时,我可以看到脚本标签中加载了脚本,但脚本未执行。

这是问题的概述,您可以在此处查看代码 https://codepen.io/Yousef-Essam/project/editor/ZJGxea

app.js提供index.html文件,然后索引文件获取script.js文件,该文件使用ajax发送两个请求以获取content.html文件和content.js文件并设置链接标记的href属性到样式文件。然后将content.js文件放入带有新内容的脚本标签中。尽管content.html已加载,样式文件也已加载,脚本已加载到script标签中,但脚本未执行。

为什么会发生这种情况,我该如何解决?

-更新-

问题可能出在使用innerHTML上,但是为什么它实际上不起作用。

此外,我认为eval可能是一个解决方案,但由于不鼓励使用eval,我希望有一个更好的解决方案

2 个答案:

答案 0 :(得分:2)

这太长了,无法发布为评论,因此我将其作为答案发布。

您正确地注意到:

  

我认为eval可能是一个解决方案,但由于不鼓励使用eval,我希望有一个更好的解决方案

实际上,eval在任何语言中都是有问题的,因为它实际上允许运行中的程序将字符串视为代码。这样做的最大问题是,这为代码注入打开了大门(用外行的术语:黑客攻击)。但是,此建议更多是理论建议,而不是有关使用什么功能的建议。

那么eval的建议是什么意思?

Eval是任何允许将字符串解释为代码的函数或机制。不同的语言具有允许eval发生的不同功能。例如,某些语言允许递归字符串插值。某些语言具有称为interp()的功能,该功能产生一个子解释器。某些语言从字面上讲有一个叫做eval()的函数。

JavaScript具有四种评估机制:

  1. 使用eval()函数。

    • 传递给eval()的任何字符串都被视为代码。
  2. 设置脚本标签的src属性

    • 假设src属性的值是要下载的javascript文件
    • 这既适用于文字代码(HTML本身中的实际代码),也适用于动态生成的脚本标签(在javascript中创建脚本元素并设置其src属性)
  3. 脚本标记的正文

    • 脚本标签内的任何文本均被视为代码
    • 这仅适用于文字代码。如您所知,禁止使用innerHTML设置脚本主体(自Netscape 4 –第一个使用javascript的浏览器以来)
  4. javascript: URI协议

    • :之后的所有内容都视为代码
    • 这仅在用户单击链接时有效

因此,您要尝试执行的是执行eval。无论您是否使用eval函数都无关紧要,您仍在尝试使用eval进行innerHTML(尽管不起作用)

因此,如果一切都是eval,有没有一种在页面上运行javascript的安全方法?

有-至少对于现代浏览器而言。

现代浏览器实现了称为 subresource integrity 的功能。不幸的是,在编写此答案时,Edge不支持它。基本上,您可以计算js文件的哈希值(例如sha1),并在script标签中对其进行声明,以便浏览器可以确认js文件未被篡改。以下是一个示例:

<script src="https://cdn.example.com/script.js"
 integrity="sha384-+/M6kredJcxdsqkczBUjMLvqyHb1K/JThDXWsBVxMEeZHEaMKEOEct339VItX1zB"></script>

你是这个偏执狂吗?

这取决于。 eval问题对您可能真的很重要。如果是这样,从设置了子资源完整性的外部源加载javascript是执行javascript的唯一安全方法。

但不是每个人都如此偏执。到目前为止,我们通常在没有此功能的情况下做得很好。以下是一些经验法则,无论您使用script标记还是调用eval(),它们都可以缓解代码泄漏:

  1. 始终确保您仅执行静态javascript代码。不要尝试从字符串构造代码。

  2. 如果必须从字符串构造代码(例如,使用诸如Handlebars之类的模板语言或使用诸如Webpack或Browserify之类的捆绑器),则切勿在代码中包含任何用户生成的内容。您仍然可以通过发出Ajax请求而不是将其包含在代码中来加载内容。

  3. 如果您必须在代码中包含用户生成的内容,而不要确保对内容进行清理。有几种普遍接受的策略,例如禁止使用特殊字符(例如<>"或转义特殊字符)。甚至还有库将为您做到这一点。

基本上我们要避免的情况是用户输入John"; console.log("gotcha");"作为他们的名字,并且能够执行代码。

答案 1 :(得分:1)

HTML规范不允许解析使用innerHTML(按照生活标准中的note under the text property description)在页面加载后动态添加为HTML标签的SCRIPT元素。

在不使用eval来解析脚本的情况下,类似问题的答案在一次简单的搜索中并不明显-尽管它们可能存在,但我只看到了场外展示的替代技术。

这是一个不使用eval的动态加载器。由于脚本的加载是异步的,因此它使用(err, data类型的回调函数来指示何时可以调用脚本。

function loadScript( url, callback) {
    var el = document.createElement("SCRIPT");
    el.type = "text/javascript";
    function finish( err) {
        callback( err, err ? false : true);
    }
    el.onerror = finish;
    if( el.readyState){  // <= IE 10
        el.onreadystatechange = function(){
            if( this.readyState == "complete"){
                finish( null);
            }
        };
    }
    else { 
        el.onload = function() { finish(null) };
    }
    el.setAttribute("async", true);
    el.src = url;
    document.getElementsByTagName("HEAD")[0].appendChild( el);
} 

// example call to load jQuery 3.2.1         

loadScript( "https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js",
   function (err, ok) {
       if( err) {
           console.log( "loading failed: " + err);
        }
        else {
         console.log( "loading success");
        }
    }
);