我有一些与XML-RPC后端通信的JavaScript代码。 XML-RPC返回如下形式的字符串:

<img src='myimage.jpg'>

然而,当我使用JavaScript将字符串插入到HTML中时,它们会逐字呈现。我看到的不是图像,而是字符串:

<img src='myimage.jpg'>

我猜想HTML是通过XML-RPC通道转义的。

如何在JavaScript中解除字符串转义?我尝试了这个页面上的技巧,但没有成功:http://paulschreiber.com/blog/2008/09/20/javascript-how-to-unescape-html-entities/

诊断这个问题的其他方法是什么?


当前回答

我在我的项目中使用了这个方法:受到其他答案的启发,但有一个额外的安全参数,在处理装饰字符时很有用

var decodeEntities=(function(){

    var el=document.createElement('div');
    return function(str, safeEscape){

        if(str && typeof str === 'string'){

            str=str.replace(/\</g, '&lt;');

            el.innerHTML=str;
            if(el.innerText){

                str=el.innerText;
                el.innerText='';
            }
            else if(el.textContent){

                str=el.textContent;
                el.textContent='';
            }

            if(safeEscape)
                str=str.replace(/\</g, '&lt;');
        }
        return str;
    }
})();

它的可用性如下:

var label='safe <b> character &eacute;ntity</b>';
var safehtml='<div title="'+decodeEntities(label)+'">'+decodeEntities(label, true)+'</div>';

其他回答

如果你正在使用jQuery:

function htmlDecode(value){ 
  return $('<div/>').html(value).text(); 
}

否则,使用Strictly Software的Encoder对象,它有一个很棒的htmlDecode()函数。

当前投票最多的答案有从字符串中删除HTML的缺点。如果这不是你想要的(这当然不是问题的一部分),那么我建议使用正则表达式来查找HTML实体(/&[^;]*;/gmi),然后遍历匹配并转换它们。

function decodeHTMLEntities(str) { if (typeof str !== 'string') { return false; } var element = document.createElement('div'); return str.replace(/&[^;]*;/gmi, entity => { entity = entity.replace(/</gm, '&lt;'); element.innerHTML = entity; return element.textContent; }); } var encoded_str = `<b>&#8593; &#67;&#65;&#78;'&#84;&nbsp;&#72;&#65;&#67;&#75;&nbsp;&#77;&#69;,&nbsp;&#66;&#82;&#79;</b>`; var decoded_str = decodeHTMLEntities(encoded_str); console.log(decoded_str);

关于XSS攻击:

虽然innerHTML不执行<script>标签中的代码,但有可能在*事件属性中运行代码,因此用户传递的字符串可能会利用上面的正则表达式:

&<img src='asdfa' error='alert(`doin\' me a hack`)' />;

因此,有必要将任何<字符转换为它们的&lt;在将它们放入隐藏的div元素之前。

此外,为了覆盖我所有的基础,我将注意到,在全局作用域中定义的函数可以通过在控制台上重新定义它们来重写,因此使用const定义这个函数或将其放在非全局作用域中非常重要。

注意:以下示例中企图利用的漏洞会使堆栈片段编辑器混淆,因为它所做的预处理,所以您必须在浏览器的控制台中运行它,或者在它自己的文件中运行它才能查看结果。

var tests = [
  "here's a spade: &spades;!",
  "&<script>alert('hackerman')</script>;",
  "&<img src='asdfa' error='alert(`doin\' me a hack`)' />;",
  "<b>&#8593; &#67;&#65;&#78;'&#84;&nbsp;&#72;&#65;&#67;&#75;&nbsp;&#77;&#69;,&nbsp;&#66;&#82;&#79;</b>"
];

var decoded = tests.map(decodeHTMLEntities).join("\n");
console.log(decoded);

结果是:

here's a spade: ♠!
&<script>alert('hackerman')</script>;
&<img src='asdfa' error='alert(`doin' me a hack`)' />;
<b>↑ CAN'T HACK ME, BRO</b>

jQuery将为您编码和解码。但是,您需要使用textarea标签,而不是div。

var str1 = 'One & two & three'; var str2 = "One &amp; two &amp; three"; $(document).ready(function() { $("#encoded").text(htmlEncode(str1)); $("#decoded").text(htmlDecode(str2)); }); function htmlDecode(value) { return $("<textarea/>").html(value).text(); } function htmlEncode(value) { return $('<textarea/>').text(value).html(); } <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> <div id="encoded"></div> <div id="decoded"></div>

你需要解码所有编码的HTML实体或只是&本身?

如果你只需要处理&然后你可以这样做:

var decoded = encoded.replace(/&amp;/g, '&');

如果你需要解码所有HTML实体,那么你可以不使用jQuery:

var elem = document.createElement('textarea');
elem.innerHTML = encoded;
var decoded = elem.value;

请注意下面Mark的评论,他强调了这个答案早期版本中的安全漏洞,并建议使用textarea而不是div来减轻潜在的XSS漏洞。无论使用jQuery还是纯JavaScript,这些漏洞都存在。

闭包可以避免创建不必要的对象。

const decodingHandler = (() => {
  const element = document.createElement('div');
  return text => {
    element.innerHTML = text;
    return element.textContent;
  };
})();

一种更简洁的方式

const decodingHandler = (() => {
  const element = document.createElement('div');
  return text => ((element.innerHTML = text), element.textContent);
})();