HTML 实体是 HTML 表达特殊字符的机制——那些直接写入会被解析器误读的字符,比如会被当作标签起始符的尖括号,或者特殊符号如版权标志、货币符号。实体用错了,轻则页面显示乱码,重则产生 XSS 漏洞。本文覆盖常用实体参考、转义规则,以及在代码中如何正确编解码。
什么是 HTML 实体?
HTML 实体是以 & 开头、; 结尾的字符串,代表单个字符。有两种形式:
命名实体使用描述性关键词:
< → <
> → >
& → &
" → "
→ (不换行空格)
数字实体使用 Unicode 码点,支持十进制和十六进制:
< → < (十进制)
< → < (十六进制)
© → ©
© → ©
两种形式输出结果完全相同。命名实体可读性强;数字实体覆盖所有 Unicode 字符,包括没有命名实体的字符。
为什么要用 HTML 实体?
防止 HTML 结构被破坏
< 和 > 在 HTML 中有特殊含义。如果需要在页面上显示字面上的尖括号,必须转义:
<!-- 错误:浏览器把这里当作未闭合的标签 -->
<p>推荐使用 <strong> 而非 <b> 来加粗文本。</p>
<!-- 正确 -->
<p>推荐使用 <strong> 而非 <b> 来加粗文本。</p>
防止 XSS 漏洞
把用户输入直接拼接进 HTML 是最常见的 Web 安全漏洞之一。如果用户输入 <script>alert(1)</script>,而你的代码原封不动地输出,这段脚本就会在每个访客的浏览器上执行。
<!-- 危险:直接输出用户输入 -->
<p>你好,<%= username %></p>
<!-- 安全:HTML 编码后输出 -->
<p>你好,<%= htmlEncode(username) %></p>
对所有插入 HTML 的用户输入,必须转义这五个字符:
| 字符 | 实体 |
|---|---|
& | & |
< | < |
> | > |
" | " |
' | ' |
兼容不同字符集环境
在 UTF-8 成为标准之前,Latin-1 编码的文档无法直接表示 ©、€、— 等字符,实体是当时的解决方案。现代项目统一用 UTF-8,这类字符可以直接写入 HTML,但实体在某些遗留系统或限制环境中仍有用。
常用 HTML 实体速查
保留字符
| 字符 | 说明 | 命名实体 | 数字实体 |
|---|---|---|---|
< | 小于号 | < | < |
> | 大于号 | > | > |
& | 和号 | & | & |
" | 双引号 | " | " |
' | 单引号 | ' | ' |
排版符号
| 字符 | 说明 | 实体 | 使用场景 |
|---|---|---|---|
| 不换行空格 | | 防止两个词之间换行 |
— | 破折号(长) | — | 句子中断、范围表示 |
– | 短横线(中) | – | 数字范围(2010–2024) |
… | 省略号 | … | 文字截断 |
" | 左双引号 | “ | 引用 |
" | 右双引号 | ” | 引用 |
常用符号
| 字符 | 说明 | 实体 |
|---|---|---|
© | 版权 | © |
® | 注册商标 | ® |
™ | 商标 | ™ |
€ | 欧元 | € |
£ | 英镑 | £ |
¥ | 日元/人民币 | ¥ |
° | 度 | ° |
± | 正负号 | ± |
× | 乘号 | × |
÷ | 除号 | ÷ |
→ | 右箭头 | → |
← | 左箭头 | ← |
数学符号
| 字符 | 说明 | 实体 |
|---|---|---|
≤ | 小于等于 | ≤ |
≥ | 大于等于 | ≥ |
≠ | 不等于 | ≠ |
∞ | 无穷大 | ∞ |
∑ | 求和 | ∑ |
√ | 根号 | √ |
在代码中编解码
JavaScript
浏览器环境借助 DOM 实现编解码:
// 编码(转义 HTML)
function htmlEncode(str) {
const div = document.createElement('div');
div.appendChild(document.createTextNode(str));
return div.innerHTML;
}
htmlEncode('<script>alert(1)</script>');
// "<script>alert(1)</script>"
// 解码
function htmlDecode(str) {
const div = document.createElement('div');
div.innerHTML = str;
return div.textContent;
}
htmlDecode('<b>加粗</b>');
// "<b>加粗</b>"
Node.js 环境(无 DOM)使用 he 库:
npm install he
import he from 'he';
he.encode('<script>alert(1)</script>');
he.decode('<b>加粗</b>');
Python(标准库)
import html
# 编码
html.escape('<script>alert(1)</script>')
# '<script>alert(1)</script>'
# 编码(包含单引号)
html.escape("这是'测试'", quote=True)
# '这是'测试''
# 解码
html.unescape('<b>你好 & 世界</b>')
# '<b>你好 & 世界</b>'
PHP
// 编码(安全输出到 HTML)
htmlspecialchars('<script>alert(1)</script>', ENT_QUOTES, 'UTF-8');
// <script>alert(1)</script>
// 编码所有适用字符
htmlentities('© 2024', ENT_QUOTES, 'UTF-8');
// © 2024
// 解码
html_entity_decode('<b>加粗</b>', ENT_QUOTES, 'UTF-8');
// <b>加粗</b>
什么时候编码,什么时候不需要
必须编码的情况: 把用户输入、外部 API 数据或任何不可信内容插入 HTML 时,一定要编码。
避免重复编码: 如果内容已经编码过(数据库里存的是 <),再编码一次会得到 &lt;,页面上显示的是字面字符串 < 而不是 <。
UTF-8 文档直接用 Unicode 字符: 现代项目统一 UTF-8,©、€、→ 可以直接写入 HTML,不需要实体。只有在遗留系统或字符集受限的邮件模板等场景才需要使用实体。
少用: 常被用来充当间距或防止换行。现代 CSS 的 white-space: nowrap 或 word-break 更可维护,可以替代大多数 的使用场景。
在线快速查询
需要找某个字符的实体,或者看到源码里的实体想知道它代表什么,用在线工具最快。试用 ZeroTool HTML 实体编解码工具 →
粘贴含有实体的 HTML 文本即可解码,输入特殊字符即可获取对应实体。适合用来:
- 解码 CMS 导出内容中的乱码实体
- 查找某个视觉符号的对应实体名称
- 验证模板转义是否正确生效
小结
HTML 实体的核心用途只有两个:一是显示保留字符而不破坏 HTML 结构,二是转义用户输入防止 XSS。现代 UTF-8 文档里,日常只需要记住 <、>、&、" 和 ' 这五个,其他字符直接用 Unicode 写即可。