我可以在javascript中转义html特殊字符吗?


201

我想通过javascript函数将文本显示为HTML。如何在JS中转义html特殊字符?是否有API?


11
这不是重复的,因为此问题不会询问jQuery。我只对此感兴趣,因为我不使用jQuery ...
lvella

Answers:


330
function escapeHtml(unsafe) {
    return unsafe
         .replace(/&/g, "&")
         .replace(/</g, "&lt;")
         .replace(/>/g, "&gt;")
         .replace(/"/g, "&quot;")
         .replace(/'/g, "&#039;");
 }

11
为什么是“&#039;” 而不是“’” ?
sereda


2
我认为replace()调用中的正则表达式是不必要的。普通的旧单字符字符串也可以。
jamix 2014年

22
@jamix您不能用原始字符串进行全局替换,而现代浏览器引擎可以很好地优化简单的正则表达式。
比约恩德(Bjornd)

5
是否有任何标准的API或这是唯一的方法?
Sunil Garg

55

function escapeHtml(html){
  var text = document.createTextNode(html);
  var p = document.createElement('p');
  p.appendChild(text);
  return p.innerHTML;
}

// Escape while typing & print result
document.querySelector('input').addEventListener('input', e => {
  console.clear();
  console.log( escapeHtml(e.target.value) );
});
<input style='width:90%; padding:6px;' placeholder='&lt;b&gt;cool&lt;/b&gt;'>


在这里工作,但

48

您可以使用jQuery的.text()功能

例如:

http://jsfiddle.net/9H6Ch/

从有关该.text()功能的jQuery文档中:

我们需要注意的是,此方法会转义必要时提供的字符串,以便将其正确呈现为HTML。为此,它调用DOM方法.createTextNode(),而不将字符串解释为HTML。

jQuery文档的先前版本是这样写的(重点增加了):

我们需要注意的是,此方法会转义必要时提供的字符串,以便将其正确呈现为HTML。为此,它调用DOM方法.createTextNode(),该方法将特殊字符替换为其HTML实体等效项(例如&lt; for <)。


3
如果您只想像这样转换,甚至可以在一个新元素上使用它:const str = "foo<>'\"&"; $('<div>').text(str).html()yieldsfoo&lt;&gt;'"&amp;
amoebe

28

我想我找到了正确的方法...

// Create a DOM Text node:
var text_node = document.createTextNode(unescaped_text);

// Get the HTML element where you want to insert the text into:
var elem = document.getElementById('msg_span');

// Optional: clear its old contents
//elem.innerHTML = '';

// Append the text node into it:
elem.appendChild(text_node);

我今天学到了一些有关HTML的新知识。w3schools.com/jsref/met_document_createtextnode.asp
Sellorio

1
请注意,如果尝试按以下方式访问文本节点,则该文本节点的内容不会转义:document.createTextNode("<script>alert('Attack!')</script>").textContent
maechler

如果您要做的只是设置文本,这是正确的方法。这也是textContent,但显然没有得到很好的支持。但是,如果您要构建一个包含某些部分文本和html的字符串,则仍然需要转义。
jgmjgm


20

到目前为止,这是我所看到的最快的方法。另外,它无需添加,删除或更改页面上的元素即可完成所有操作。

function escapeHTML(unsafeText) {
    let div = document.createElement('div');
    div.innerText = unsafeText;
    return div.innerHTML;
}

7
警告:它不会转义引号,因此您不能在HTML代码中的属性值内部使用输出。例如,var divCode = '<div data-title="' + escapeHTML('Jerry "Bull" Winston') + '">Div content</div>'将产生无效的HTML!
izogfif

17

找到更好的解决方案很有趣:

var escapeHTML = function(unsafe) {
  return unsafe.replace(/[&<"']/g, function(m) {
    switch (m) {
      case '&':
        return '&amp;';
      case '<':
        return '&lt;';
      case '"':
        return '&quot;';
      default:
        return '&#039;';
    }
  });
};

我不解析,>因为它不会破坏结果中的XML / HTML代码。

这里是基准测试:http : //jsperf.com/regexpairs 另外,我创建了一个通用escape函数:http : //jsperf.com/regexpairs2


1
有趣的是,使用该开关的速度明显快于地图。没想到这个!感谢分享!
Peter T.

Unicode字符比您可能编码和考虑的更多得多。我完全不会推荐这种手动方法。
vsync

您为什么要完全转义多字节字符?随处使用UTF-8。
Neonit

4
跳过>可能会破坏代码。您必须记住,<>内也是html。在这种情况下,跳过>将会中断。如果只在标签之间转义,则可能只需要转义<和&。
jgmjgm

8

显示未编码文本的最简洁,最高效的方法是使用textContentproperty。

比使用更快innerHTML。而且这还没有考虑到转义开销。

document.body.textContent = 'a <b> c </b>';


@ZzZombo,它与样式和脚本标签不兼容是完全正常的。在向他们添加内容时,在这种情况下,您添加的代码不是text,而是使用innerHTML。而且,您不需要对其进行转义,这是两个未解析为HTML的特殊标记。解析时,将其内容视为文本,直到满足关闭顺序为止</
用户

6

DOM元素通过分配给innerText支持将文本转换为HTML 。innerText不是函数,但是对其进行赋值就像将文本转义一样。

document.querySelectorAll('#id')[0].innerText = 'unsafe " String >><>';

1
至少在Chrome中,分配多行文字会添加<br>元素来代替换行符,而换行符会破坏某些元素,例如样式或脚本。在createTextNode不容易出现这个问题。
ZzZombo

1
innerText有一些遗留/规格问题。更好地使用textContent
罗伊·廷克

3

您可以对字符串中的每个字符进行编码:

function encode(e){return e.replace(/[^]/g,function(e){return"&#"+e.charCodeAt(0)+";"})}

或仅针对主要字符来担心(&,inebreaks,<,>,“和'),例如:

function encode(r){
return r.replace(/[\x26\x0A\<>'"]/g,function(r){return"&#"+r.charCodeAt(0)+";"})
}

test.value=encode('How to encode\nonly html tags &<>\'" nice & fast!');

/*************
* \x26 is &ampersand (it has to be first),
* \x0A is newline,
*************/
<textarea id=test rows="9" cols="55">&#119;&#119;&#119;&#46;&#87;&#72;&#65;&#75;&#46;&#99;&#111;&#109;</textarea>


编写自己的转义功能通常是一个坏主意。在这方面,其他答案更好。
jannis '16

2

一线(适用于ES6 +):

var escapeHtml = s => (s + '').replace(/[&<>"']/g, m => ({
    '&': '&amp;', '<': '&lt;', '>': '&gt;',
    '"': '&quot;', "'": '&#39;'
})[m]);

对于旧版本:

function escapeHtml(s) {
    return (s + '').replace(/[&<>"']/g, function (m) {
        return ({
            '&': '&amp;', '<': '&lt;', '>': '&gt;',
            '"': '&quot;', "'": '&#39;'
        })[m];
    });
}

0

在构建DOM结构时遇到了这个问题。这个问题帮助我解决了。我想使用双V形作为路径分隔符,但是附加一个新的文本节点直接导致显示转义的字符代码,而不是字符本身:

var _div = document.createElement('div');
var _separator = document.createTextNode('&raquo;');
//_div.appendChild(_separator); /* this resulted in '&raquo;' being displayed */
_div.innerHTML = _separator.textContent; /* this was key */

0

如果您已经在应用程序中使用模块,则可以使用escape-html模块。

import escapeHtml from 'escape-html';
const unsafeString = '<script>alert("XSS");</script>';
const safeString = escapeHtml(unsafeString);


-4

我想出了这个解决方案。

假设我们要向元素添加一些HTML,其中包含来自用户或数据库的不安全数据。

var unsafe = 'some unsafe data like <script>alert("oops");</script> here';

var html = '';
html += '<div>';
html += '<p>' + unsafe + '</p>';
html += '</div>';

element.html(html);

这对于XSS攻击是不安全的。现在添加它。

$(document.createElement('div')).html(unsafe).text();

就是这样

var unsafe = 'some unsafe data like <script>alert("oops");</script> here';

var html = '';
html += '<div>';
html += '<p>' + $(document.createElement('div')).html(unsafe).text(); + '</p>';
html += '</div>';

element.html(html);

对我来说,这比使用起来容易得多.replace(),它将删除!!!所有可能的html标签(我希望)。


这是一个危险的想法,它将不安全的HTML字符串解析为HTML,如果该元素附加到将执行的DOM上。使用.innerText代替。
teknopaul '17

这不安全。转换&lt;script&gt;<script>
fgb
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.