从输入字段读取属性时 HTML 编码丢失

Posted

技术标签:

【中文标题】从输入字段读取属性时 HTML 编码丢失【英文标题】:HTML-encoding lost when attribute read from input field 【发布时间】:2012-12-30 01:31:59 【问题描述】:

我正在使用 javascript 从隐藏字段中提取一个值并将其显示在文本框中。隐藏字段中的值被编码。

例如,

<input id='hiddenId' type='hidden' value='chalk &amp; cheese' />

被拉进

<input type='text' value='chalk &amp; cheese' />

通过一些 jQuery 从隐藏字段中获取值(此时我丢失了编码):

$('#hiddenId').attr('value')

问题是当我从隐藏字段中读取chalk &amp;amp; cheese 时,JavaScript 似乎丢失了编码。我不希望值为chalk &amp; cheese。我希望保留文字 amp;

是否有可以对字符串进行 html 编码的 JavaScript 库或 jQuery 方法?

【问题讨论】:

你能显示你正在使用的 Javascript 吗? 添加了我如何从隐藏字段中获取价值 不要使用 innerHTML 方法(jQuery .html() 方法使用 innerHTML),因为在某些(我只测试过 Chrome)浏览器上,这不会转义引号,所以如果你是将您的值放入属性值中,您最终会遇到 XSS 漏洞。 在什么情况下chalkcheese曾经一起使用0_o @d-_-b 比较两个项目时。例子。它们就像粉笔和奶酪一样不同;) 【参考方案1】:

编辑: 这个答案是很久以前发布的,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。

【讨论】:

这适用于大多数情况,但 htmlDecode 的这种实现将消除任何额外的空白。因此对于“输入”的某些值,输入!= htmlDecode(htmlEncode(input))。在某些情况下,这对我们来说是个问题。例如,如果 input = "

\t Hi \n There

",则往返编码/解码将产生 "

Hi There

"。大多数时候这没关系,但有时不是。 :)
取决于浏览器,在 Firefox 上它包括空格、换行符...在 IE 上它会剥离所有内容。【参考方案2】:

jQuery 技巧不对引号进行编码,在 IE 中它会去掉你的空格。

基于 Django 中的 escape 模板标签,我猜它已经被大量使用/测试过,我制作了这个功能来满足需要。

可以说,它比任何解决空格剥离问题的解决方法都更简单(并且可能更快) - 它对引号进行编码,例如,如果您要在属性值中使用结果,这是必不可少的。

function htmlEscape(str) 
    return str
        .replace(/&/g, '&amp;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#39;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;');


// I needed the opposite function today, so adding here too:
function htmlUnescape(str)
    return str
        .replace(/&quot;/g, '"')
        .replace(/&#39;/g, "'")
        .replace(/&lt;/g, '<')
        .replace(/&gt;/g, '>')
        .replace(/&amp;/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 年 3 月 4 日更新: 我刚刚注意到 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 年 4 月 6 日更新: 您可能还希望转义正斜杠/。这不是正确的 HTML 编码所必需的,但它是 recommended by OWASP 作为反 XSS 安全措施。 (感谢@JNF 在 cmets 中的建议)

        .replace(/\//g, '&#x2F;');

【讨论】:

@Ferruccio ...以及为什么不使用 '见:***.com/questions/2083754/…blogs.msdn.com/b/kirillosenkov/archive/2010/03/19/…fishbowl.pastiche.org/2003/07/01/the_curse_of_apos【参考方案3】:

这是一个非 jQuery 版本,它比 jQuery .html() 版本和 .replace() 版本快得多。这会保留所有空格,但与 jQuery 版本一样,它不处理引号。

function htmlEncode( html ) 
    return document.createElement( 'a' ).appendChild( 
        document.createTextNode( html ) ).parentNode.innerHTML;
;

速度: http://jsperf.com/htmlencoderegex/17

演示:

输出:

脚本:

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>   &amp; hello</div>';
document.getElementById( 'same' ).textContent = 
      'html === htmlDecode( htmlEncode( html ) ): ' 
    + ( html === htmlDecode( htmlEncode( html ) ) );

HTML:

<input id="hidden" type="hidden" value="chalk    &amp; cheese" />
<input id="text" value="" />
<div id="same"></div>

【讨论】:

这引出了一个问题:为什么它不是 JS 中的全局函数?!【参考方案4】:

我知道这是一个旧的,但我想发布一个 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();
 

【讨论】:

【参考方案5】:

Underscore 提供了执行此操作的 _.escape()_.unescape() 方法。

> _.unescape( "chalk &amp; cheese" );
  "chalk & cheese"

> _.escape( "chalk & cheese" );
  "chalk &amp; cheese"

【讨论】:

【参考方案6】:

很好的答案。请注意,如果使用 jQuery 1.4.2 编码的值是 undefinednull,您可能会收到如下错误:

jQuery("&lt;div/&gt;").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('&lt;div/&gt;').text(value || '').html()【参考方案7】:

对于那些喜欢纯javascript的人,这是我成功使用的方法:

function escapeHTML (str)

    var div = document.createElement('div');
    var text = document.createTextNode(str);
    div.appendChild(text);
    return div.innerHTML;

【讨论】:

【参考方案8】:

FWIW,编码没有丢失。编码在页面加载期间由标记解析器(浏览器)使用。一旦源代码被读取和解析并且浏览器将 DOM 加载到内存中,编码就被解析为它所代表的内容。所以当你的 JS 被执行以读取内存中的任何内容时,它得到的字符就是编码所代表的内容。

我可能在这里严格按照语义操作,但我希望您了解编码的目的。 “丢失”这个词让人听起​​来好像有些事情没有按应有的方式工作。

【讨论】:

【参考方案9】:

没有 Jquery 更快。您可以对字符串中的每个字符进行编码:

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('Encode HTML entities!\n\n"Safe" escape <script id=\'\'> & useful in <pre> tags!');

testing.innerHTML=test.value;

/*************
* \x26 is &ampersand (it has to be first),
* \x0A is newline,
*************/
<textarea id=test rows="9" cols="55"></textarea>

<div id="testing">www.WHAK.com</div>

【讨论】:

【参考方案10】:

Prototype 内置于String class。因此,如果您正在使用/计划使用 Prototype,它会执行以下操作:

'<div class="article">This is an article</div>'.escapeHTML();
// -> "&lt;div class="article"&gt;This is an article&lt;/div&gt;"

【讨论】:

在查看了 Prototype 的解决方案之后,这就是它所做的一切…….replace(/&amp;/g,'&amp;amp;').replace(/&lt;/g,'&amp;lt;').replace(/&gt;/g,'&amp;gt;'); 很简单。 不应该用引号做点什么吗?这不好【参考方案11】:

这是一个简单的 javascript 解决方案。它使用“HTMLEncode”方法扩展 String 对象,该方法可用于不带参数或带参数的对象。

String.prototype.HTMLEncode = function(str) 
  var result = "";
  var str = (arguments.length===1) ? str : this;
  for(var i=0; i<str.length; i++) 
     var chrcode = str.charCodeAt(i);
     result+=(chrcode>128) ? "&#"+chrcode+";" : str.substr(i,1)
   
   return result;

// TEST
console.log("stetaewteaw æø".HTMLEncode());
console.log("stetaewteaw æø".HTMLEncode("æåøåæå"))

我已经发了gist "HTMLEncode method for javascript"。

【讨论】:

【参考方案12】:

基于angular's sanitize...(es6模块语法)

// ref: https://github.com/angular/angular.js/blob/v1.3.14/src/ngSanitize/sanitize.js
const SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
const NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g;

const decodeElem = document.createElement('pre');


/**
 * Decodes html encoded text, so that the actual string may
 * be used.
 * @param value
 * @returns string decoded text
 */
export function decode(value) 
  if (!value) return '';
  decodeElem.innerHTML = value.replace(/</g, '&lt;');
  return decodeElem.textContent;



/**
 * Encodes all potentially dangerous characters, so that the
 * resulting string can be safely inserted into attribute or
 * element text.
 * @param value
 * @returns string encoded text
 */
export function encode(value) 
  if (value === null || value === undefined) return '';
  return String(value).
    replace(/&/g, '&amp;').
    replace(SURROGATE_PAIR_REGEXP, value => 
      var hi = value.charCodeAt(0);
      var low = value.charCodeAt(1);
      return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';';
    ).
    replace(NON_ALPHANUMERIC_REGEXP, value => 
      return '&#' + value.charCodeAt(0) + ';';
    ).
    replace(/</g, '&lt;').
    replace(/>/g, '&gt;');


export default encode,decode;

【讨论】:

虽然我真的很喜欢这个答案,实际上我认为这是一个很好的方法,但我有疑问,if (value === null | value === undefined) return ''; 上的按位运算符是错字还是实际上是一个功能?如果是这样,为什么要使用那个而不是常见的 || ?谢谢!! @AlejandroVales 我很确定这是一个错字...已更正。 无论如何请记住 |将导致 0 或 1,所以实际上它确实有效 ^^ 你不能用== null吗? undefined 是唯一与 null 等价的东西,所以无论如何都不需要两个三等号 这根本不是真的。 null0 都是假的,是的,所以你不能只做 !value,但 == 的全部意义在于让某些事情变得更容易。 0 == null 是假的。 undefined == null 是真的。你可以做value == null【参考方案13】:

据我所知,javascript 中没有任何直接的 HTML 编码/解码方法。

但是,你可以做的是,使用 JS 创建任意元素,设置其内部文本,然后使用 innerHTML 读取它。

假设使用 jQuery,这应该可以工作:

var helper = $('chalk & cheese').hide().appendTo('body');
var htmled = helper.html();
helper.remove();

或者类似的东西。

【讨论】:

我觉得投反对票有点有趣,考虑到这个答案几乎与有超过 870 个赞成票的答案相同,并且在这个答案之后发布了一点。【参考方案14】:

您不必为了将值从一个输入字段传送到另一个输入字段而对值进行转义/编码。

<form>
 <input id="button" type="button" value="Click me">
 <input type="hidden" id="hiddenId" name="hiddenId" value="I like cheese">
 <input type="text" id="output" name="output">
</form>
<script>
    $(document).ready(function(e) 
        $('#button').click(function(e) 
            $('#output').val($('#hiddenId').val());
        );
    );
</script>

JS 不会插入原始 HTML 或任何东西;它只是告诉 DOM 设置 value 属性(或属性;不确定)。无论哪种方式,DOM 都会为您处理任何编码问题。除非你做一些奇怪的事情,比如使用document.writeeval,否则 HTML 编码将是有效透明的。

如果您正在谈论生成一个新的文本框来保存结果......它仍然很容易。只需将 HTML 的静态部分传递给 jQuery,然后在它返回给您的对象上设置其余的属性/属性。

$box = $('<input type="text" name="whatever">').val($('#hiddenId').val());

【讨论】:

【参考方案15】:

我遇到了类似的问题,并使用 JavaScript (documentation) 中的函数 encodeURIComponent 解决了它

例如,在您的情况下,如果您使用:

<input id='hiddenId' type='hidden' value='chalk & cheese' />

encodeURIComponent($('#hiddenId').attr('value'))

你会得到chalk%20%26%20cheese。甚至保留空格。

在我的例子中,我必须编码一个反斜杠,这段代码可以完美运行

encodeURIComponent('name/surname')

我得到了name%2Fsurname

【讨论】:

【参考方案16】:

这里有一点模仿微软 ASP 中的 Server.HTMLEncode 函数,用纯 JavaScript 编写:

function htmlEncode(s) 
  var ntable = 
    "&": "amp",
    "<": "lt",
    ">": "gt",
    "\"": "quot"
  ;
  s = s.replace(/[&<>"]/g, function(ch) 
    return "&" + ntable[ch] + ";";
  )
  s = s.replace(/[^ -\x7e]/g, function(ch) 
    return "&#" + ch.charCodeAt(0).toString() + ";";
  );
  return s;

结果对撇号进行编码,但对其他 HTML 特殊字符和 0x20-0x7e 范围之外的任何字符进行编码。

【讨论】:

【参考方案17】:

我的纯 JS 函数:

/**
 * HTML entities encode
 *
 * @param string str Input text
 * @return string Filtered text
 */
function htmlencode (str)

  var div = document.createElement('div');
  div.appendChild(document.createTextNode(str));
  return div.innerHTML;

JavaScript HTML Entities Encode & Decode

【讨论】:

【参考方案18】:

如果你想使用 jQuery。我发现了这个:

http://www.jquerysdk.com/api/jQuery.htmlspecialchars

(jQuery SDK 提供的 jquery.string 插件的一部分)

我认为 Prototype 的问题在于它扩展了 JavaScript 中的基础对象,并且与您可能使用过的任何 jQuery 都不兼容。当然,如果你已经在使用 Prototype 而不是 jQuery,那也不是问题。

编辑:还有这个,它是原型的 jQuery 字符串实用程序的一个端口:

http://stilldesigning.com/dotstring/

【讨论】:

【参考方案19】:
var htmlEnDeCode = (function() 
    var charToEntityRegex,
        entityToCharRegex,
        charToEntity,
        entityToChar;

    function resetCharacterEntities() 
        charToEntity = ;
        entityToChar = ;
        // add the default set
        addCharacterEntities(
            '&amp;'     :   '&',
            '&gt;'      :   '>',
            '&lt;'      :   '<',
            '&quot;'    :   '"',
            '&#39;'     :   "'"
        );
    

    function addCharacterEntities(newEntities) 
        var charKeys = [],
            entityKeys = [],
            key, echar;
        for (key in newEntities) 
            echar = newEntities[key];
            entityToChar[key] = echar;
            charToEntity[echar] = key;
            charKeys.push(echar);
            entityKeys.push(key);
        
        charToEntityRegex = new RegExp('(' + charKeys.join('|') + ')', 'g');
        entityToCharRegex = new RegExp('(' + entityKeys.join('|') + '|&#[0-9]1,5;' + ')', 'g');
    

    function htmlEncode(value)
        var htmlEncodeReplaceFn = function(match, capture) 
            return charToEntity[capture];
        ;

        return (!value) ? value : String(value).replace(charToEntityRegex, htmlEncodeReplaceFn);
    

    function htmlDecode(value) 
        var htmlDecodeReplaceFn = function(match, capture) 
            return (capture in entityToChar) ? entityToChar[capture] : String.fromCharCode(parseInt(capture.substr(2), 10));
        ;

        return (!value) ? value : String(value).replace(entityToCharRegex, htmlDecodeReplaceFn);
    

    resetCharacterEntities();

    return 
        htmlEncode: htmlEncode,
        htmlDecode: htmlDecode
    ;
)();

这是来自 ExtJS 的源代码。

【讨论】:

【参考方案20】:
<script>
String.prototype.htmlEncode = function () 
    return String(this)
        .replace(/&/g, '&amp;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#39;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;');



var aString = '<script>alert("I hack your site")</script>';
console.log(aString.htmlEncode());
</script>

将输出:&amp;lt;script&amp;gt;alert(&amp;quot;I hack your site&amp;quot;)&amp;lt;/script&amp;gt;

.htmlEncode() 一旦定义,所有字符串都可以访问。

【讨论】:

【参考方案21】:

HtmlEncodes 给定的值

  var htmlEncodeContainer = $('<div />');
  function htmlEncode(value) 
    if (value) 
      return htmlEncodeContainer.text(value).html();
     else 
      return '';
    
  

【讨论】:

【参考方案22】:

我在域\用户字符串中遇到了一些反斜杠问题。

我将此添加到 Anentropic 回答的其他逃逸中

.replace(/\\/g, '&#92;')

我在这里找到的: How to escape backslash in JavaScript?

【讨论】:

【参考方案23】:

在prototype.js中挑选escapeHTML()在做什么

添加此脚本可帮助您转义HTML:

String.prototype.escapeHTML = function()  
    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;')

现在您可以在脚本中的字符串上调用 escapeHTML 方法,例如:

var escapedString = "<h1>this is HTML</h1>".escapeHTML();
// gives: "&lt;h1&gt;this is HTML&lt;/h1&gt;"

希望它可以帮助任何寻求简单解决方案的人,而不必包含整个prototype.js

【讨论】:

【参考方案24】:

使用此处的其他一些答案,我制作了一个版本,该版本可以一次性替换所有相关字符,而与不同编码字符的数量无关(仅调用一次 replace()),因此对于较大的字符串会更快。

它不依赖 DOM API 的存在或其他库。

window.encodeHTML = (function() 
    function escapeRegex(s) 
        return s.replace(/[-\/\\^$*+?.()|[\]]/g, '\\$&');
    
    var encodings = 
        '&'  : '&amp;',
        '"'  : '&quot;',
        '\'' : '&#39;',
        '<'  : '&lt;',
        '>'  : '&gt;',
        '\\' : '&#x2F;'
    ;
    function encode(what)  return encodings[what]; ;
    var specialChars = new RegExp('[' +
        escapeRegex(Object.keys(encodings).join('')) +
    ']', 'g');

    return function(text)  return text.replace(specialChars, encode); ;
)();

运行一次后,您现在可以调用

encodeHTML('<>&"\'')

获取&amp;lt;&amp;gt;&amp;amp;&amp;quot;&amp;#39;

【讨论】:

【参考方案25】:

function encodeHTML(str) 
    return document.createElement("a").appendChild( 
        document.createTextNode(str)).parentNode.innerHTML;
;

function decodeHTML(str) 
    var element = document.createElement("a"); 
    element.innerHTML = str;
    return element.textContent;
;
var str = "<"
var enc = encodeHTML(str);
var dec = decodeHTML(enc);
console.log("str: " + str, "\nenc: " + enc, "\ndec: " + dec);

【讨论】:

【参考方案26】:

亡灵术。 这当然不需要 jQuery! 这是来自 System.Web.HttpUtility 的 JavaScript 端口(C# - 免责声明:未经过充分测试):

"use strict";
function htmlDecode(s) 
    if (s == null)
        return null;
    if (s.length == 0)
        return "";
    if (s.indexOf('&') == -1)
        return s;
    function isDigit(str) 
        return /^\d+$/.test(str);
    
    function isHexDigit(str) 
        return /[0-9A-Fa-f]6/g.test(str);
    
    function initEntities() 
        var entities = ;
        entities["nbsp"] = '\u00A0';
        entities["iexcl"] = '\u00A1';
        entities["cent"] = '\u00A2';
        entities["pound"] = '\u00A3';
        entities["curren"] = '\u00A4';
        entities["yen"] = '\u00A5';
        entities["brvbar"] = '\u00A6';
        entities["sect"] = '\u00A7';
        entities["uml"] = '\u00A8';
        entities["copy"] = '\u00A9';
        entities["ordf"] = '\u00AA';
        entities["laquo"] = '\u00AB';
        entities["not"] = '\u00AC';
        entities["shy"] = '\u00AD';
        entities["reg"] = '\u00AE';
        entities["macr"] = '\u00AF';
        entities["deg"] = '\u00B0';
        entities["plusmn"] = '\u00B1';
        entities["sup2"] = '\u00B2';
        entities["sup3"] = '\u00B3';
        entities["acute"] = '\u00B4';
        entities["micro"] = '\u00B5';
        entities["para"] = '\u00B6';
        entities["middot"] = '\u00B7';
        entities["cedil"] = '\u00B8';
        entities["sup1"] = '\u00B9';
        entities["ordm"] = '\u00BA';
        entities["raquo"] = '\u00BB';
        entities["frac14"] = '\u00BC';
        entities["frac12"] = '\u00BD';
        entities["frac34"] = '\u00BE';
        entities["iquest"] = '\u00BF';
        entities["Agrave"] = '\u00C0';
        entities["Aacute"] = '\u00C1';
        entities["Acirc"] = '\u00C2';
        entities["Atilde"] = '\u00C3';
        entities["Auml"] = '\u00C4';
        entities["Aring"] = '\u00C5';
        entities["AElig"] = '\u00C6';
        entities["Ccedil"] = '\u00C7';
        entities["Egrave"] = '\u00C8';
        entities["Eacute"] = '\u00C9';
        entities["Ecirc"] = '\u00CA';
        entities["Euml"] = '\u00CB';
        entities["Igrave"] = '\u00CC';
        entities["Iacute"] = '\u00CD';
        entities["Icirc"] = '\u00CE';
        entities["Iuml"] = '\u00CF';
        entities["ETH"] = '\u00D0';
        entities["Ntilde"] = '\u00D1';
        entities["Ograve"] = '\u00D2';
        entities["Oacute"] = '\u00D3';
        entities["Ocirc"] = '\u00D4';
        entities["Otilde"] = '\u00D5';
        entities["Ouml"] = '\u00D6';
        entities["times"] = '\u00D7';
        entities["Oslash"] = '\u00D8';
        entities["Ugrave"] = '\u00D9';
        entities["Uacute"] = '\u00DA';
        entities["Ucirc"] = '\u00DB';
        entities["Uuml"] = '\u00DC';
        entities["Yacute"] = '\u00DD';
        entities["THORN"] = '\u00DE';
        entities["szlig"] = '\u00DF';
        entities["agrave"] = '\u00E0';
        entities["aacute"] = '\u00E1';
        entities["acirc"] = '\u00E2';
        entities["atilde"] = '\u00E3';
        entities["auml"] = '\u00E4';
        entities["aring"] = '\u00E5';
        entities["aelig"] = '\u00E6';
        entities["ccedil"] = '\u00E7';
        entities["egrave"] = '\u00E8';
        entities["eacute"] = '\u00E9';
        entities["ecirc"] = '\u00EA';
        entities["euml"] = '\u00EB';
        entities["igrave"] = '\u00EC';
        entities["iacute"] = '\u00ED';
        entities["icirc"] = '\u00EE';
        entities["iuml"] = '\u00EF';
        entities["eth"] = '\u00F0';
        entities["ntilde"] = '\u00F1';
        entities["ograve"] = '\u00F2';
        entities["oacute"] = '\u00F3';
        entities["ocirc"] = '\u00F4';
        entities["otilde"] = '\u00F5';
        entities["ouml"] = '\u00F6';
        entities["divide"] = '\u00F7';
        entities["oslash"] = '\u00F8';
        entities["ugrave"] = '\u00F9';
        entities["uacute"] = '\u00FA';
        entities["ucirc"] = '\u00FB';
        entities["uuml"] = '\u00FC';
        entities["yacute"] = '\u00FD';
        entities["thorn"] = '\u00FE';
        entities["yuml"] = '\u00FF';
        entities["fnof"] = '\u0192';
        entities["Alpha"] = '\u0391';
        entities["Beta"] = '\u0392';
        entities["Gamma"] = '\u0393';
        entities["Delta"] = '\u0394';
        entities["Epsilon"] = '\u0395';
        entities["Zeta"] = '\u0396';
        entities["Eta"] = '\u0397';
        entities["Theta"] = '\u0398';
        entities["Iota"] = '\u0399';
        entities["Kappa"] = '\u039A';
        entities["Lambda"] = '\u039B';
        entities["Mu"] = '\u039C';
        entities["Nu"] = '\u039D';
        entities["Xi"] = '\u039E';
        entities["Omicron"] = '\u039F';
        entities["Pi"] = '\u03A0';
        entities["Rho"] = '\u03A1';
        entities["Sigma"] = '\u03A3';
        entities["Tau"] = '\u03A4';
        entities["Upsilon"] = '\u03A5';
        entities["Phi"] = '\u03A6';
        entities["Chi"] = '\u03A7';
        entities["Psi"] = '\u03A8';
        entities["Omega"] = '\u03A9';
        entities["alpha"] = '\u03B1';
        entities["beta"] = '\u03B2';
        entities["gamma"] = '\u03B3';
        entities["delta"] = '\u03B4';
        entities["epsilon"] = '\u03B5';
        entities["zeta"] = '\u03B6';
        entities["eta"] = '\u03B7';
        entities["theta"] = '\u03B8';
        entities["iota"] = '\u03B9';
        entities["kappa"] = '\u03BA';
        entities["lambda"] = '\u03BB';
        entities["mu"] = '\u03BC';
        entities["nu"] = '\u03BD';
        entities["xi"] = '\u03BE';
        entities["omicron"] = '\u03BF';
        entities["pi"] = '\u03C0';
        entities["rho"] = '\u03C1';
        entities["sigmaf"] = '\u03C2';
        entities["sigma"] = '\u03C3';
        entities["tau"] = '\u03C4';
        entities["upsilon"] = '\u03C5';
        entities["phi"] = '\u03C6';
        entities["chi"] = '\u03C7';
        entities["psi"] = '\u03C8';
        entities["omega"] = '\u03C9';
        entities["thetasym"] = '\u03D1';
        entities["upsih"] = '\u03D2';
        entities["piv"] = '\u03D6';
        entities["bull"] = '\u2022';
        entities["hellip"] = '\u2026';
        entities["prime"] = '\u2032';
        entities["Prime"] = '\u2033';
        entities["oline"] = '\u203E';
        entities["frasl"] = '\u2044';
        entities["weierp"] = '\u2118';
        entities["image"] = '\u2111';
        entities["real"] = '\u211C';
        entities["trade"] = '\u2122';
        entities["alefsym"] = '\u2135';
        entities["larr"] = '\u2190';
        entities["uarr"] = '\u2191';
        entities["rarr"] = '\u2192';
        entities["darr"] = '\u2193';
        entities["harr"] = '\u2194';
        entities["crarr"] = '\u21B5';
        entities["lArr"] = '\u21D0';
        entities["uArr"] = '\u21D1';
        entities["rArr"] = '\u21D2';
        entities["dArr"] = '\u21D3';
        entities["hArr"] = '\u21D4';
        entities["forall"] = '\u2200';
        entities["part"] = '\u2202';
        entities["exist"] = '\u2203';
        entities["empty"] = '\u2205';
        entities["nabla"] = '\u2207';
        entities["isin"] = '\u2208';
        entities["notin"] = '\u2209';
        entities["ni"] = '\u220B';
        entities["prod"] = '\u220F';
        entities["sum"] = '\u2211';
        entities["minus"] = '\u2212';
        entities["lowast"] = '\u2217';
        entities["radic"] = '\u221A';
        entities["prop"] = '\u221D';
        entities["infin"] = '\u221E';
        entities["ang"] = '\u2220';
        entities["and"] = '\u2227';
        entities["or"] = '\u2228';
        entities["cap"] = '\u2229';
        entities["cup"] = '\u222A';
        entities["int"] = '\u222B';
        entities["there4"] = '\u2234';
        entities["sim"] = '\u223C';
        entities["cong"] = '\u2245';
        entities["asymp"] = '\u2248';
        entities["ne"] = '\u2260';
        entities["equiv"] = '\u2261';
        entities["le"] = '\u2264';
        entities["ge"] = '\u2265';
        entities["sub"] = '\u2282';
        entities["sup"] = '\u2283';
        entities["nsub"] = '\u2284';
        entities["sube"] = '\u2286';
        entities["supe"] = '\u2287';
        entities["oplus"] = '\u2295';
        entities["otimes"] = '\u2297';
        entities["perp"] = '\u22A5';
        entities["sdot"] = '\u22C5';
        entities["lceil"] = '\u2308';
        entities["rceil"] = '\u2309';
        entities["lfloor"] = '\u230A';
        entities["rfloor"] = '\u230B';
        entities["lang"] = '\u2329';
        entities["rang"] = '\u232A';
        entities["loz"] = '\u25CA';
        entities["spades"] = '\u2660';
        entities["clubs"] = '\u2663';
        entities["hearts"] = '\u2665';
        entities["diams"] = '\u2666';
        entities["quot"] = '\u0022';
        entities["amp"] = '\u0026';
        entities["lt"] = '\u003C';
        entities["gt"] = '\u003E';
        entities["OElig"] = '\u0152';
        entities["oelig"] = '\u0153';
        entities["Scaron"] = '\u0160';
        entities["scaron"] = '\u0161';
        entities["Yuml"] = '\u0178';
        entities["circ"] = '\u02C6';
        entities["tilde"] = '\u02DC';
        entities["ensp"] = '\u2002';
        entities["emsp"] = '\u2003';
        entities["thinsp"] = '\u2009';
        entities["zwnj"] = '\u200C';
        entities["zwj"] = '\u200D';
        entities["lrm"] = '\u200E';
        entities["rlm"] = '\u200F';
        entities["ndash"] = '\u2013';
        entities["mdash"] = '\u2014';
        entities["lsquo"] = '\u2018';
        entities["rsquo"] = '\u2019';
        entities["sbquo"] = '\u201A';
        entities["ldquo"] = '\u201C';
        entities["rdquo"] = '\u201D';
        entities["bdquo"] = '\u201E';
        entities["dagger"] = '\u2020';
        entities["Dagger"] = '\u2021';
        entities["permil"] = '\u2030';
        entities["lsaquo"] = '\u2039';
        entities["rsaquo"] = '\u203A';
        entities["euro"] = '\u20AC';
        return entities;
    
    var Entities = initEntities();
    var rawEntity = [];
    var entity = [];
    var output = [];
    var len = s.length;
    var state = 0;
    var number = 0;
    var is_hex_value = false;
    var have_trailing_digits = false;
    for (var i = 0; i < len; i++) 
        var c = s[i];
        if (state == 0) 
            if (c == '&') 
                entity.push(c);
                rawEntity.push(c);
                state = 1;
            
            else 
                output.push(c);
            
            continue;
        
        if (c == '&') 
            state = 1;
            if (have_trailing_digits) 
                entity.push(number.toString());
                have_trailing_digits = false;
            
            output.push(entity.join(""));
            entity = [];
            entity.push('&');
            continue;
        
        if (state == 1) 
            if (c == ';') 
                state = 0;
                output.push(entity.join(""));
                output.push(c);
                entity = [];
            
            else 
                number = 0;
                is_hex_value = false;
                if (c != '#') 
                    state = 2;
                
                else 
                    state = 3;
                
                entity.push(c);
                rawEntity.push(c);
            
        
        else if (state == 2) 
            entity.push(c);
            if (c == ';') 
                var key = entity.join("");
                if (key.length > 1 && Entities.hasOwnProperty(key.substr(1, key.length - 2)))
                    key = Entities[key.substr(1, key.length - 2)].toString();
                output.push(key);
                state = 0;
                entity = [];
                rawEntity = [];
            
        
        else if (state == 3) 
            if (c == ';') 
                if (number == 0)
                    output.push(rawEntity.join("") + ";");
                else if (number > 65535) 
                    output.push("&#");
                    output.push(number.toString());
                    output.push(";");
                
                else 
                    output.push(String.fromCharCode(number));
                
                state = 0;
                entity = [];
                rawEntity = [];
                have_trailing_digits = false;
            
            else if (is_hex_value && isHexDigit(c)) 
                number = number * 16 + parseInt(c, 16);
                have_trailing_digits = true;
                rawEntity.push(c);
            
            else if (isDigit(c)) 
                number = number * 10 + (c.charCodeAt(0) - '0'.charCodeAt(0));
                have_trailing_digits = true;
                rawEntity.push(c);
            
            else if (number == 0 && (c == 'x' || c == 'X')) 
                is_hex_value = true;
                rawEntity.push(c);
            
            else 
                state = 2;
                if (have_trailing_digits) 
                    entity.push(number.toString());
                    have_trailing_digits = false;
                
                entity.push(c);
            
        
    
    if (entity.length > 0) 
        output.push(entity.join(""));
    
    else if (have_trailing_digits) 
        output.push(number.toString());
    
    return output.join("");

function htmlEncode(s) 
    if (s == null)
        return null;
    if (s.length == 0)
        return s;
    var needEncode = false;
    for (var i = 0; i < s.length; i++) 
        var c = s[i];
        if (c == '&' || c == '"' || c == '<' || c == '>' || c.charCodeAt(0) > 159
            || c == '\'') 
            needEncode = true;
            break;
        
    
    if (!needEncode)
        return s;
    var output = [];
    var len = s.length;
    for (var i = 0; i < len; i++) 
        var ch = s[i];
        switch (ch) 
            case '&':
                output.push("&amp;");
                break;
            case '>':
                output.push("&gt;");
                break;
            case '<':
                output.push("&lt;");
                break;
            case '"':
                output.push("&quot;");
                break;
            case '\'':
                output.push("&#39;");
                break;
            case '\uff1c':
                output.push("&#65308;");
                break;
            case '\uff1e':
                output.push("&#65310;");
                break;
            default:
                if (ch.charCodeAt(0) > 159 && ch.charCodeAt(0) < 256) 
                    output.push("&#");
                    output.push(ch.charCodeAt(0).toString());
                    output.push(";");
                
                else
                    output.push(ch);
                break;
        
    
    return output.join("");

【讨论】:

以上是关于从输入字段读取属性时 HTML 编码丢失的主要内容,如果未能解决你的问题,请参考以下文章

当表单包含大量输入时,表单数据被截断/丢失?

从下拉列表中选择数据时,从 MYSQL 数据库中设置输入字段值属性

为什么HttpWebResponse会丢失数据?

shp转geojson并解决属性丢失或属性中文乱码方法

如何使用python套接字从html获取输入

如何防止孩子在 fork() 之后干扰父母的标准输入