
HTML 转义字符显示为原始文本而不是渲染效果
常见现象是页面上直接看到 <、 这类字符串,而不是对应的 或空格。本质是浏览器把转义序列当作了普通文本,没触发 HTML 解析。
根本原因通常是:你用 JS 赋值给 innerText 或 textContent,或者服务端返回的字符串被框架(如 React/Vue)自动做了二次转义。
- 用
innerHTML替代innerText可让浏览器解析转义字符,但注意 XSS 风险——只对可信内容用 - React 中写
{'<div>'}会原样输出,得用dangerouslySetInnerHTML={{__html: '<div>'}} - Vue 模板里用
v-html,而非双大括号插值 - 后端返回 JSON 时如果已转义过一次(如 Python 的
html.escape()),前端再手动拼接就容易叠成
Python 里 html.unescape() 和 html.escape() 怎么选
处理用户输入或存储 HTML 内容时,html.escape() 是防 XSS 的第一道关;读取并展示时,html.unescape() 才能还原成可渲染的符号。
典型误用:从数据库读出带 " 的字段,直接塞进模板,结果引号不显示——其实该先 html.unescape()。
立即学习“前端免费学习笔记(深入)”;
-
html.escape('<script>')</script>→'<script>'(安全存入 HTML 上下文) -
html.unescape('<p>Hello World</p>')→'<p>Hello World</p><div class="aritcle_card flexRow"> <div class="artcardd flexRow"> <a class="aritcle_card_img" href="/ai/1175" title="Spacely AI"><img src="https://img.php.cn/upload/ai_manual/000/000/000/175680102422753.jpg" alt="Spacely AI" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a> <div class="aritcle_card_info flexColumn"> <a href="/ai/1175" title="Spacely AI">Spacely AI</a> <p>为您的房间提供AI室内设计解决方案,寻找无限的创意</p> </div> <a href="/ai/1175" title="Spacely AI" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div>'(准备渲染) - 注意:
html.unescape()不处理 Unicode 实体(如😊),需额外用codecs.decode(s, 'unicode_escape')
JS 中 decodeURIComponent() 不能替代 HTML 转义解码
很多人看到 %26lt; 就下意识用 decodeURIComponent(),但它只解 URL 编码,不是 HTML 实体。混用会导致 < 变成 还是乱码,取决于原始编码层级。
真正要解 HTML 实体,浏览器环境最稳的是临时 DOM 元素法:
function htmlUnescape(str) {
const div = document.createElement('div');
div.innerHTML = str;
return div.textContent || div.innerText || '';
}
- 不要用正则手动替换
<等——实体有上百种,还有十进制、十六进制 <code> - Node.js 环境可用
he库:const he = require('he'); he.unescape('<') -
DOMParser也可,但比临时 div 开销大,没必要
富文本编辑器保存后显示异常: 消失或变成空格
编辑器(如 TinyMCE、Quill)默认把连续空格转成 存储,但前后端传输或模板渲染时若忽略空白处理规则,就会塌陷。
关键点在于:CSS 的 white-space 属性和 HTML 解析行为必须匹配。
- 存库前确保用
html.escape()(Python)或DOMPurify.sanitize()(JS)保留,别被过滤掉 - 渲染时容器加 CSS:
white-space: pre-wrap;,否则浏览器把当普通空格合并 - 检查是否在 JS 中用
.trim()或正则/\s+/g处理过内容——会干掉对应的 Unicode 字符\u00a0
实体转义不是“一劳永逸”的开关,它嵌在输入、存储、传输、渲染四个环节里,漏掉任意一层, 就可能变成看不见的坑。









