HTML 实体是 HTML 表达特殊字符的机制——那些直接写入会被解析器误读的字符,比如会被当作标签起始符的尖括号,或者特殊符号如版权标志、货币符号。实体用错了,轻则页面显示乱码,重则产生 XSS 漏洞。本文覆盖常用实体参考、转义规则,以及在代码中如何正确编解码。

什么是 HTML 实体?

HTML 实体是以 & 开头、; 结尾的字符串,代表单个字符。有两种形式:

命名实体使用描述性关键词:

&lt;<
&gt;    → >
&amp;   → &
&quot;  → "
&nbsp;  → (不换行空格)

数字实体使用 Unicode 码点,支持十进制和十六进制:

&#60;<   (十进制)
&#x3C;<   (十六进制)
&#169;   → ©
&#x00A9; → ©

两种形式输出结果完全相同。命名实体可读性强;数字实体覆盖所有 Unicode 字符,包括没有命名实体的字符。

为什么要用 HTML 实体?

防止 HTML 结构被破坏

<> 在 HTML 中有特殊含义。如果需要在页面上显示字面上的尖括号,必须转义:

<!-- 错误:浏览器把这里当作未闭合的标签 -->
<p>推荐使用 <strong> 而非 <b> 来加粗文本。</p>

<!-- 正确 -->
<p>推荐使用 &lt;strong&gt; 而非 &lt;b&gt; 来加粗文本。</p>

防止 XSS 漏洞

把用户输入直接拼接进 HTML 是最常见的 Web 安全漏洞之一。如果用户输入 <script>alert(1)</script>,而你的代码原封不动地输出,这段脚本就会在每个访客的浏览器上执行。

<!-- 危险:直接输出用户输入 -->
<p>你好,<%= username %></p>

<!-- 安全:HTML 编码后输出 -->
<p>你好,<%= htmlEncode(username) %></p>

对所有插入 HTML 的用户输入,必须转义这五个字符:

字符实体
&&amp;
<&lt;
>&gt;
"&quot;
'&#39;

兼容不同字符集环境

在 UTF-8 成为标准之前,Latin-1 编码的文档无法直接表示 © 等字符,实体是当时的解决方案。现代项目统一用 UTF-8,这类字符可以直接写入 HTML,但实体在某些遗留系统或限制环境中仍有用。

常用 HTML 实体速查

保留字符

字符说明命名实体数字实体
<小于号&lt;&#60;
>大于号&gt;&#62;
&和号&amp;&#38;
"双引号&quot;&#34;
'单引号&#39;&#x27;

排版符号

字符说明实体使用场景
不换行空格&nbsp;防止两个词之间换行
破折号(长)&mdash;句子中断、范围表示
短横线(中)&ndash;数字范围(2010–2024)
省略号&hellip;文字截断
"左双引号&ldquo;引用
"右双引号&rdquo;引用

常用符号

字符说明实体
©版权&copy;
®注册商标&reg;
商标&trade;
欧元&euro;
£英镑&pound;
¥日元/人民币&yen;
°&deg;
±正负号&plusmn;
×乘号&times;
÷除号&divide;
右箭头&rarr;
左箭头&larr;

数学符号

字符说明实体
小于等于&le;
大于等于&ge;
不等于&ne;
无穷大&infin;
求和&sum;
根号&radic;

在代码中编解码

JavaScript

浏览器环境借助 DOM 实现编解码:

// 编码(转义 HTML)
function htmlEncode(str) {
  const div = document.createElement('div');
  div.appendChild(document.createTextNode(str));
  return div.innerHTML;
}

htmlEncode('<script>alert(1)</script>');
// "&lt;script&gt;alert(1)&lt;/script&gt;"

// 解码
function htmlDecode(str) {
  const div = document.createElement('div');
  div.innerHTML = str;
  return div.textContent;
}

htmlDecode('&lt;b&gt;加粗&lt;/b&gt;');
// "<b>加粗</b>"

Node.js 环境(无 DOM)使用 he 库:

npm install he
import he from 'he';

he.encode('<script>alert(1)</script>');
he.decode('&lt;b&gt;加粗&lt;/b&gt;');

Python(标准库)

import html

# 编码
html.escape('<script>alert(1)</script>')
# '&lt;script&gt;alert(1)&lt;/script&gt;'

# 编码(包含单引号)
html.escape("这是'测试'", quote=True)
# '这是&#x27;测试&#x27;'

# 解码
html.unescape('&lt;b&gt;你好 &amp; 世界&lt;/b&gt;')
# '<b>你好 & 世界</b>'

PHP

// 编码(安全输出到 HTML)
htmlspecialchars('<script>alert(1)</script>', ENT_QUOTES, 'UTF-8');
// &lt;script&gt;alert(1)&lt;/script&gt;

// 编码所有适用字符
htmlentities('© 2024', ENT_QUOTES, 'UTF-8');
// &copy; 2024

// 解码
html_entity_decode('&lt;b&gt;加粗&lt;/b&gt;', ENT_QUOTES, 'UTF-8');
// <b>加粗</b>

什么时候编码,什么时候不需要

必须编码的情况: 把用户输入、外部 API 数据或任何不可信内容插入 HTML 时,一定要编码。

避免重复编码: 如果内容已经编码过(数据库里存的是 &lt;),再编码一次会得到 &amp;lt;,页面上显示的是字面字符串 &lt; 而不是 <

UTF-8 文档直接用 Unicode 字符: 现代项目统一 UTF-8,© 可以直接写入 HTML,不需要实体。只有在遗留系统或字符集受限的邮件模板等场景才需要使用实体。

&nbsp; 少用: &nbsp; 常被用来充当间距或防止换行。现代 CSS 的 white-space: nowrapword-break 更可维护,可以替代大多数 &nbsp; 的使用场景。

在线快速查询

需要找某个字符的实体,或者看到源码里的实体想知道它代表什么,用在线工具最快。试用 ZeroTool HTML 实体编解码工具 →

粘贴含有实体的 HTML 文本即可解码,输入特殊字符即可获取对应实体。适合用来:

  • 解码 CMS 导出内容中的乱码实体
  • 查找某个视觉符号的对应实体名称
  • 验证模板转义是否正确生效

小结

HTML 实体的核心用途只有两个:一是显示保留字符而不破坏 HTML 结构,二是转义用户输入防止 XSS。现代 UTF-8 文档里,日常只需要记住 &lt;&gt;&amp;&quot;&#39; 这五个,其他字符直接用 Unicode 写即可。

立即使用 HTML 实体编解码工具 →