我正在使用 JavaScript 从隐藏字段中提取值并将其显示在文本框中。隐藏字段中的值被编码。
例如,
<input id='hiddenId' type='hidden' value='chalk & cheese' />
被拉进
<input type='text' value='chalk & cheese' />
通过一些 jQuery 从隐藏字段中获取值(此时我丢失了编码):
$('#hiddenId').attr('value')
问题是当我从隐藏字段中读取 chalk & cheese
时,JavaScript 似乎丢失了编码。我不希望值为 chalk & cheese
。我希望保留文字 amp;
。
是否有可以对字符串进行 HTML 编码的 JavaScript 库或 jQuery 方法?
chalk
和 cheese
曾经一起使用 0_o
编辑: 这个答案是很久以前发布的,htmlDecode
函数引入了 XSS 漏洞。它已被修改,将临时元素从 div
更改为 textarea
,从而减少了 XSS 机会。但是现在,我鼓励您按照 other anwswer 中的建议使用 DOMParser API。
我使用这些功能:
function htmlEncode(value){
// Create a in-memory element, set its inner text (which is automatically encoded)
// Then grab the encoded contents back out. The element never exists on the DOM.
return $('<textarea/>').text(value).html();
}
function htmlDecode(value){
return $('<textarea/>').html(value).text();
}
基本上一个 textarea 元素是在内存中创建的,但它永远不会附加到文档中。
在 htmlEncode
函数上,我设置元素的 innerText
,并检索编码的 innerHTML
;在 htmlDecode
函数上,我设置元素的 innerHTML
值并检索 innerText
。
检查一个正在运行的示例 here。
jQuery 技巧不编码引号,在 IE 中它会去掉你的空格。
基于 Django 中的转义模板标签,我猜它已经被大量使用/测试过,我制作了这个函数来满足需要。
它可以说比空白剥离问题的任何解决方法都更简单(并且可能更快) - 它对引号进行编码,例如,如果您要在属性值中使用结果,这是必不可少的。
function htmlEscape(str) {
return str
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/</g, '<')
.replace(/>/g, '>');
}
// I needed the opposite function today, so adding here too:
function htmlUnescape(str){
return str
.replace(/"/g, '"')
.replace(/'/g, "'")
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/&/g, '&');
}
2013 年 6 月 17 日更新:
在寻找最快转义的过程中,我发现了一个 replaceAll
方法的实现:
http://dumpsite.com/forum/index.php?topic=4.msg29#msg29
(也在这里引用: Fastest method to replace all instances of a character in a string)
这里有一些性能结果:
http://jsperf.com/htmlencoderegex/25
它为上面的内置 replace
链提供相同的结果字符串。如果有人能解释为什么它更快,我会很高兴!?
2015-03-04 更新:
我刚刚注意到 AngularJS 正在使用上述方法:
https://github.com/angular/angular.js/blob/v1.3.14/src/ngSanitize/sanitize.js#L435
他们添加了一些改进 - 他们似乎正在处理 obscure Unicode issue 以及将所有非字母数字字符转换为实体。我的印象是,只要您为文档指定了 UTF8 字符集,就不需要后者。
我会注意到(4 年后)Django 仍然没有做这些事情,所以我不确定它们有多重要:
https://github.com/django/django/blob/1.8b1/django/utils/html.py#L44
2016-04-06 更新:
您可能还希望转义正斜杠 /
。这不是正确的 HTML 编码所必需的,但它是 recommended by OWASP 作为一种反 XSS 安全措施。 (感谢@JNF 在评论中提出这个建议)
.replace(/\//g, '/');
这是一个比 jQuery .html()
版本和 .replace()
版本快得多的非 jQuery 版本。这会保留所有空格,但与 jQuery 版本一样,它不处理引号。
function htmlEncode( html ) {
return document.createElement( 'a' ).appendChild(
document.createTextNode( html ) ).parentNode.innerHTML;
};
速度: http://jsperf.com/htmlencoderegex/17
https://i.stack.imgur.com/NI3c4.png
输出:
https://i.stack.imgur.com/zE07Z.png
脚本:
function htmlEncode( html ) {
return document.createElement( 'a' ).appendChild(
document.createTextNode( html ) ).parentNode.innerHTML;
};
function htmlDecode( html ) {
var a = document.createElement( 'a' ); a.innerHTML = html;
return a.textContent;
};
document.getElementById( 'text' ).value = htmlEncode( document.getElementById( 'hidden' ).value );
//sanity check
var html = '<div> & hello</div>';
document.getElementById( 'same' ).textContent =
'html === htmlDecode( htmlEncode( html ) ): '
+ ( html === htmlDecode( htmlEncode( html ) ) );
HTML:
<input id="hidden" type="hidden" value="chalk & cheese" />
<input id="text" value="" />
<div id="same"></div>
我知道这是一个旧的,但我想发布一个 the accepted answer 的变体,它可以在 IE 中工作而不会删除行:
function multiLineHtmlEncode(value) {
var lines = value.split(/\r\n|\r|\n/);
for (var i = 0; i < lines.length; i++) {
lines[i] = htmlEncode(lines[i]);
}
return lines.join('\r\n');
}
function htmlEncode(value) {
return $('<div/>').text(value).html();
}
Underscore 提供了执行此操作的 _.escape()
和 _.unescape()
方法。
> _.unescape( "chalk & cheese" );
"chalk & cheese"
> _.escape( "chalk & cheese" );
"chalk & cheese"
好答案。请注意,如果使用 jQuery 1.4.2 编码的值为 undefined
或 null
,您可能会收到如下错误:
jQuery("<div/>").text(value).html is not a function
或者
Uncaught TypeError: Object has no method 'html'
解决方案是修改函数以检查实际值:
function htmlEncode(value){
if (value) {
return jQuery('<div/>').text(value).html();
} else {
return '';
}
}
jQuery('<div/>').text(value || '').html()
对于那些喜欢纯 javascript 的人,这是我成功使用的方法:
function escapeHTML (str)
{
var div = document.createElement('div');
var text = document.createTextNode(str);
div.appendChild(text);
return div.innerHTML;
}
FWIW,编码没有丢失。在页面加载期间,标记解析器(浏览器)使用编码。一旦源代码被读取和解析并且浏览器将 DOM 加载到内存中,编码就被解析为它所代表的内容。因此,当您的 JS 被执行以读取内存中的任何内容时,它获得的字符就是编码所代表的内容。
我可能在这里严格按照语义操作,但我希望您了解编码的目的。 “丢失”这个词让人听起来好像有些东西没有按应有的方式工作。
没有 Jquery 更快。您可以对字符串中的每个字符进行编码:
function encode(e){return e.replace(/[^]/g,function(e){return"&#"+e.charCodeAt(0)+";"})}
或者只针对主要角色担心(&,inebreaks,<,>,“和'),例如:
函数编码(r){ return r.replace(/[\x26\x0A\<>'"]/g,function(r){return""+r.charCodeAt(0)+";"}) } test.value=encode('编码 HTML 实体!\n\n"Safe" 转义
\t Hi \n There
",则往返编码/解码将产生 "Hi There
"。大多数时候这没关系,但有时不是。 :)