为什么在渲染部分之前使用escape_javascript?

119 javascript ruby-on-rails

我正在看这个Railscast插曲,并想知道为什么escape_javascript需要这里的电话:

$("#reviews").append("<%= escape_javascript(render(:partial => @review)) %>");
Run Code Online (Sandbox Code Playgroud)

什么escape_javascript用于?

根据Rails文档:

escape_javascript(JavaScript的)

转义运营商返回以及JavaScript细分的单引号和双引号.

但这对我来说并不重要.

kik*_*ito 359

如果将代码分为两部分,则更容易理解.

第一部分$("#reviews").append("<%= ... %>");是带有erb的javascript.这意味着<%= ... %>将被它内部的ruby代码返回的任何内容替换.替换的结果必须是有效的javascript,否则当客户端尝试处理它时会抛出错误.所以这是第一件事:你需要有效的javascript.

另一件需要考虑的事情是,无论ruby生成什么都必须包含在带双引号的javascript字符串中 - 请注意周围的双引号<%= ... %>.这意味着生成的javascript将如下所示:

$("#reviews").append("...");
Run Code Online (Sandbox Code Playgroud)

现在让我们来看看里面的红宝石部分<%= ... %>.怎么render(:partial => @review)办?它呈现部分 - 这意味着它可以呈现任何类型的代码 - html,css ...甚至更多的javascript!

那么,如果我们的部分包含一些简单的html会发生什么呢?

<a href="/mycontroller/myaction">Action!</a> 
Run Code Online (Sandbox Code Playgroud)

请记住,您的javascript使用双引号字符串作为参数?如果我们只是用<%= ... %>那个部分的代码替换,那么我们就有了问题 - 在href=双引号之后立即出现!javascript无效:

// Without escaping, you get a broken javascript string at href
$("#reviews").append("<a href="/mycontroller/myaction">Action!</a>");
Run Code Online (Sandbox Code Playgroud)

为了不发生这种情况,你想要转义这些特殊字符,这样你的字符串就不会被剪切 - 你需要生成这个字符的东西:

<a href=\"/mycontroller/myaction\">Action!</a>
Run Code Online (Sandbox Code Playgroud)

这是escape_javascript做什么的.它确保返回的字符串不会"破坏"javascript.如果您使用它,您将获得所需的输出:

$("#reviews").append("<a href=\"/mycontroller/myaction\">Action!</a>")
Run Code Online (Sandbox Code Playgroud)

问候!

  • `escape_javascript()`现在有一个更短的方法:simpley`j()`(至少在Rails 4中). (14认同)
  • @Steve同意,一个更好的名字是'escape_for_javascript`,因为往往你逃避其他代码(HTML例如),因此它不破的JavaScript. (13认同)
  • 的确,非常好的解释谢谢.我想然后使用'escape_javascript'有点误导,因为我们实际上并没有使用它来逃避实际的javascript.您可以在部分中放置脚本标记并执行您想要的任何JavaScript. (4认同)

bar*_*ley 8

用户可能会发布恶意代码(恶意用户),如果未被转义可能会被执行,允许用户控制您的应用程序.

试试这个:

<% variable = '"); alert("hi there' %>
$("#reviews").append("<%= variable %>");
Run Code Online (Sandbox Code Playgroud)

不太熟悉rails的语法,但如果你没有逃脱,variable那么会显示一个警告框,我不认为这是预期的行为.


Tab*_*rez 8

如果你看一下这里的来源,它会更加清晰.

此功能完成以下两件事:

  1. 它将输入字符串中的字符替换为JS_ESCAPE_MAP中定义的字符

    这样做的目的是确保javascript代码正确序列化,而不会干扰嵌入它的外部字符串.例如,如果你有一个双引号的javascript字符串,那么字符串文字中的所有引号都必须用单引号来避免代码破坏.

  2. 该函数还会检查结果字符串是否为html安全.如果不是那么它会进行必要的转义以确保字符串变为html安全并返回结果.

当您使用escape_javascript时,它通常被动态地嵌入到另一个字符串或现有的html中.您需要确保这样做不会使整个页面无法呈现.

在其他响应中指出了这种响应的某些方面,但我想将所有项目结合在一起,包括javascript转义和html转义之间的区别.此外,一些回复暗示此功能有助于避免脚本注入.我认为这不是这个功能的目的.例如,在您的评论中,如果您的评论有警报('hi there'),只需将其附加到节点就不会触发弹出窗口.您没有将其嵌入在页面加载或其他事件触发的函数中.仅仅提醒('hi there')作为你的HTML的一部分并不意味着它将作为javascript执行.

这就是说我不否认脚本注入是不可能的.但是为了避免在获取用户数据并将其存储在数据库中时需要采取措施.您提供的功能和示例与呈现已保存的信息有关.

我希望这有助于回答你的问题.