如何转义或反转义 HTML
- 选择 转义 或 反转义。
- 转义时,在 转义范围 中选择要转义的内容:
- 仅 & < > " ‘:用于要粘贴到页面或模板中的 HTML。
- 外加所有非 ASCII 字符:用于不能安全处理 UTF-8 的页面、邮件或系统。
- 所有字符:对全部文本编码,用于测试解析器。
- 选择 格式:命名实体(é)、十进制(é) 或 十六进制(é)。对于没有常用名称的字符,命名实体会回退为十进制。如果文本只放在元素内容中,可以取消勾选 转义引号。
- 按 复制输出。互换 会把结果移到另一侧,便于往返检查。
反转义使用浏览器的 HTML 解析器,所以 HTML5 中 2,000 多个命名引用全都支持,十进制和十六进制引用也一样。输入永远不会被渲染为 HTML。
常用实体
| 字符 | 命名 | 十进制 | 十六进制 |
|---|---|---|---|
& | & | & | & |
< | < | < | < |
> | > | > | > |
" | " | " | " |
' | '(HTML5) | ' | ' |
| 不换行空格 | |   |   |
é | é | é | é |
— | — | — | — |
€ | € | € | € |
© | © | © | © |
😀 | 无 | 😀 | 😀 |
数字引用使用的是 Unicode 码位。这个 Emoji 在 UTF-8 中占四个字节,却只需要一个引用。
转义和解码时的陷阱
- 先转义
&。 先把<换成<,再把&换成&,就会得到&lt;。任何手写的转义器都必须先处理&,再处理其他字符。 - 文本中未编码的
&可能变成符号。 HTML 仍然能识别一些不带分号的旧式实体,所以文本?id=1©=2¶=3会显示为?id=1©=2¶=3。每个 & 符号都写成&,URL 中也一样。 - 双重转义 在页面上表现为
&lt;b&gt;。先反转义一次,再找出是哪一层转义了两次。 不是空格。 它解码为 U+00A0,看起来像空格,但在某些语言中字符串比较和trim()会对它失效。- 实体不是 URL 编码。 在链接中,HTML 源码里的
&用于分隔查询参数,而%26是值内部的字面 & 符号。后者请交给 URL 编码器。
在代码中转义和反转义
import html
html.escape('5 > 3 & "quotes"') # '5 > 3 & "quotes"'
html.unescape("Café — ©") # 'Café — ©'
const escapeHtml = s => s.replace(/&/g, "&").replace(/</g, "<")
.replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
const unescapeHtml = s =>
new DOMParser().parseFromString(s, "text/html").documentElement.textContent;
Python 的 html.escape 默认会转义引号,并把 ' 写成 '。PHP 通常用 htmlspecialchars();从 PHP 8.1 起,它默认转义两种引号。DOMParser 不会运行被解析文档中的脚本,因此在浏览器中用它解码是安全的。更多 JavaScript 字符串处理见 JavaScript 页面。
实体、Base64 与 data URI
HTML 实体和 Base64 解决的是不同的问题。实体让字符可以安全地放在 HTML 源码中;Base64 把字节变成文本,让整个文件能放进一个属性里。要把完整的 HTML 文档嵌入 data: URI 或 JSON 字段,请用 HTML 转 Base64 编码,而不是逐个转义字符。
常见问题
HTML 中哪些字符必须转义?
在文本内容中,& 和 < 必须转义,按惯例 > 也要转义。在属性值中,还要转义界定该值的引号 " 或 '。其他一切,包括带重音的字母和 Emoji,在 UTF-8 页面中都可以保持原样。
' 和 ' 有什么区别?
两者都表示撇号。' 在 HTML5 和 XML 中有定义,但 HTML 4 中没有,所以 ' 才是所有解析器和邮件客户端都认的形式。这里的转义器使用 '。
为什么我的页面上出现了 &amp;?
文本被转义了两次:& 变成 &,第二次转义又把它变成 &amp;。在这里反转义一次即可得到原本的文本,然后去掉多余的转义步骤,通常是模板引擎对已经转义过的值又转义了一遍。
转义 HTML 实体能防止 XSS 吗?
它能防止注入 HTML 文本和带引号的属性值。它不能让数据在 <script> 块、javascript: URL、CSS 或不带引号的属性中变得安全,这些上下文需要各自的编码方式。优先使用模板引擎的自动转义。