如何使用jQuery解码HTML实体?

365

我该如何使用jQuery解码字符串中的HTML实体?


过早选择技术(如jQuery)会引发安全问题的答案。这个问题最好关闭,作为 https://dev59.com/o3I-5IYBdhLWcg3wVWpi 的重复。 - Wladimir Palant
20个回答

459

安全提示:使用本答案(以下保留其原始形式)可能会在您的应用程序中引入跨站点脚本(XSS)漏洞您不应该使用这个答案。阅读lucascaro的答案以了解此答案中的漏洞,并改用Mark Amery的答案或那个答案中的方法。

实际上,试试这个:

var encodedStr = "This is fun & stuff";
var decoded = $("<div/>").html(encodedStr).text();
console.log(decoded);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div/>


182
不要使用不受信任的输入进行此操作。许多浏览器即使节点未连接到DOM也会加载图像并触发相关事件。尝试运行$("<div/>").html('<img src="http://www.google.com/images/logos/ps_logo2.png" onload=alert(1337)>')。在Firefox或Safari中,它会触发警报。 - Mike Samuel
@ Mike,那你建议用什么替代它?如果不知道要替换什么,你的.replace()答案就是无用的... - ekkis
7
@ekkis,在尝试解码实体之前,您需要删除标记。 请使用“str.replace(/</?\w(?:[^"'>]|"[^"]"|'[^']')*>/g, "")”或类似的方法。 - Mike Samuel
2
一个更好的实现(在我看来)可以从我的类似问题的答案中剥离大多数HTML标签(由Mike提供)。它也没有jQuery的开销,因此非常适合其他环境。 - Robert K
6
@MichaelStum,您的编辑使Mike Samuel的评论和下一个得票最高的答案无效,并且没有实际修复所有jQuery版本的XSS漏洞(如下面的答案所解释)。在此答案中添加安全警告是合理的(我将这样做);让页面上的其他讨论变得毫无意义,同时未能实际修复安全漏洞绝对不是好的做法! - Mark Amery
我使用了你的代码来处理带有HTML实体的WordPress API $($.parseHTML(item.title.rendered)).text() - Pranesh Janarthanan

241

没有任何jQuery:

function decodeEntities(encodedString) {
  var textArea = document.createElement('textarea');
  textArea.innerHTML = encodedString;
  return textArea.value;
}

console.log(decodeEntities('1 &amp; 2')); // '1 & 2'

这与被采纳的答案类似,但可安全地用于不受信任的用户输入。

类似方法中的安全问题

正如Mike Samuel所指出的,使用

而不是

6
在提取完文本区域的值后,销毁该文本区域可能是一个好主意: decodedString = textArea.value; textArea.remove(); return decodedString; - Werner
2
如果JavaScript的版本确实支持remove()方法,那么可以使用以下代码删除文本区域:if ('remove' in Element.prototype) textArea.remove(); - Werner
7
一旦函数退出,就不会再有变量引用它,因此它将被 垃圾回收器 自动清除。 - user2428118
我在按钮的代码后台与.NET结合使用,因为某种原因,接受的答案引起了一次回发。而这个答案没有引起回发,所以对我来说这是最好的答案。谢谢! - Snailer
@Snailer $("<div />").html(string).text() 会执行提供的字符串中的任何JavaScript,我怀疑这就是导致你问题的原因。应该将被接受的答案更新为这个。 - jbowman

82

2
这个实际上应该得到更多的赞!绝对是我首选的解决方案。顺便说一下,他们现在已经在文档中包含了 unescape - lethal-guitar
5
_.unescape("&#39;") 的结果只是 &#39; 而不是单引号。我是否遗漏了什么,或者underscore不能像http://www.w3schools.com/tags/ref_entities.asp所示的那样转义HTML实体代码? - Jason Axelson
6
该Github上的bug被标记为“不予修复”;这意味着该解决方案无效且将无法使用。 - Igor Chubin
3
你说Underscore的escapeunescape方法...对于用户输入不安全”。这是什么意思?在我看来,这听起来像无稽之谈,但也许我漏掉了什么——你能澄清一下吗? - Mark Amery
2
@VyvIT 尝试过在 Chrome / FF / IE 中使用 _.unescape("&lt;img src=fake onerror=alert('boo!')&gt;"),但它没有弹出任何警报。我已经尝试在控制台中运行它,也将其放入我的 JS 文件中。结果相同。 - Vivek Athalye
显示剩余5条评论

28

我认为你混淆了文本和HTML方法。看一下这个例子,如果你将元素的inner HTML作为文本使用,你将得到已解码的HTML标签(第二个按钮)。但是如果你将它们作为HTML使用,你将得到HTML格式化的视图(第一个按钮)。

<div id="myDiv">
    here is a <b>HTML</b> content.
</div>
<br />
<input value="Write as HTML" type="button" onclick="javascript:$('#resultDiv').html($('#myDiv').html());" />
&nbsp;&nbsp;
<input value="Write as Text" type="button" onclick="javascript:$('#resultDiv').text($('#myDiv').html());" />
<br /><br />
<div id="resultDiv">
    Results here !
</div>

第一个按钮写道:这里是一段HTML内容。

第二个按钮写道:这里是一段<B>HTML</B>内容。

顺便提一下,你可以看到我在jQuery插件 - HTML编码和解码中找到的一个插件,它可以对HTML字符串进行编码和解码。


26

这个问题受到“使用jQuery”的限制,但是对一些人有帮助的是,最佳答案中给出的jQuery代码在下面执行了以下操作... 这可以与或没有jQuery一起工作:

function decodeEntities(input) {
  var y = document.createElement('textarea');
  y.innerHTML = input;
  return y.value;
}

24

编码:

$("<textarea/>").html('<a>').html(); // return '&lt;a&gt'
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<textarea/>

解码:

$("<textarea/>").html('&lt;a&gt').val() // return '<a>'
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<textarea/>


4
已经有一个可行的答案了,而且它几乎和这个一模一样。我们不需要重复的答案。 - markasoftware
5
这是有效的答案。Tom的答案使用了DIV元素,这使得该答案容易受到XSS攻击。 - hodgef
3
这是为了清晰度而最好的答案。 - Dan Randolph
你确定它能正常工作吗?我是说可能是我的浏览器,但文本区发生的事情有点奇怪。 - Ruslan López
这是最好的安全且简短的一行解决方案。谢谢。 - Leutecia

22
你可以使用来自https://github.com/mathiasbynens/hehe库。
示例:
console.log(he.decode("J&#246;rg &amp J&#xFC;rgen rocked to &amp; fro "));
// Logs "Jörg & Jürgen rocked to & fro"

向库的作者提出了质疑,询问在客户端代码中是否有任何理由使用这个库,而不是使用其他答案中和其他地方提供的<textarea> hack。他提供了一些可能的理由:

  • 如果你使用node.js服务器端,使用一个HTML编码/解码库可以为你提供一个单一的解决方案,既适用于客户端又适用于服务器端。

  • 一些浏览器的实体解码算法存在错误或缺少对一些命名字符引用的支持。例如,Internet Explorer虽然可以正确解码和呈现非断空格(&nbsp;),但是在通过DOM元素的innerText属性报告它们时,会将它们报告为普通空格而不是非断空格,这破坏了<textarea>的hack(尽管只是轻微的)。此外,IE 8和9根本不支持HTML5中添加的任何新的命名字符引用。作者还在http://mathias.html5.org/tests/html/named-character-references/上托管了一个命名字符引用支持测试。在IE 8中,它报告了一千多个错误。

    如果你想免受与实体解码相关的浏览器错误影响,或者想能够处理全部的命名字符引用范围,那么你不能仅仅使用<textarea>的hack;你需要像he这样的库。

  • 他只是感觉这种方式做事情不那么hacky。


5
jQuery并不是解决所有问题的万能工具,要使用适合的工具来完成工作。 - Mathias Bynens
这是解码HTML实体的最佳方法。所有其他答案(在此类似的问题中)要么使用innerHTML(创建新的HTML元素,处理HTML代码,然后获取该元素的innerHTML,如果您不非常小心,这可能会容易受到XSS攻击查看更多 ),要么建议使用Underscore.js unescape或Lodash unescape方法,但两者都不完整(仅适用于少数HTML实体)。he库是最完整和安全的选项! - ands

4
尝试一下:

var htmlEntities = "&lt;script&gt;alert('hello');&lt;/script&gt;";
var htmlDecode =$.parseHTML(htmlEntities)[0]['wholeText'];
console.log(htmlDecode);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

parseHTML是Jquery库中的一个函数,它将返回一个数组,其中包含有关给定字符串的一些详细信息。

在某些情况下,字符串很大,因此该函数将把内容分成许多索引。

要获取所有索引数据,您应该转到任何索引,然后访问名为"wholeText"的索引。

我选择索引0,因为它适用于所有情况(小字符串或大字符串)。


虽然这段代码可能是解决方案,但包括解释真的有助于提高您帖子的质量。记住,您正在为未来的读者回答问题,而这些人可能不知道您提出代码建议的原因。 - Johan
说明已添加...谢谢 :) - Fawaz Al Romy
如果使用jQuery,这个问题很容易解决。 - Lizesh Shakya

3

使用

myString = myString.replace( /\&amp;/g, '&' );

因为显然JavaScript没有处理实体的本地库,而且我在各种扩展JavaScript的框架的搜索结果中也没有找到任何与之相关的内容,所以最简单的方法是在服务器端进行处理。

搜索“JavaScript HTML实体”,你可能会找到一些专门用于此目的的库,但它们可能都是基于上述逻辑构建的-逐个实体替换。


0
对于ExtJS用户,如果您已经有了编码字符串,例如当库函数的返回值是innerHTML内容时,请考虑使用以下ExtJS函数:
Ext.util.Format.htmlDecode(innerHtmlContent)

这仅适用于5个HTML实体。您可以在文档源代码中查看。 - ands

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接