HTML 字符集与编码¶
字符集描述字符集合,字符编码规定字符与字节如何映射。 现代 Web 文档应统一使用 Unicode 的 UTF-8 编码。
推荐声明¶
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>UTF-8 页面</title>
</head>
</html>
meta charset 应完整位于文档前 1024 字节内,通常紧跟在 head 开始标签后。
HTTP 与 HTML 声明¶
| 层级 | 示例 | 优先级与注意 |
|---|---|---|
| HTTP 响应头 | Content-Type: text/html; charset=utf-8 |
首选服务端声明,作用于整个响应 |
| HTML 元数据 | <meta charset="utf-8"> |
供浏览器早期嗅探和本地文件使用 |
| 旧式 HTML 元数据 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> |
历史兼容写法,新文档不需要 |
| BOM | UTF-8 字节序标记 | 可识别但非必需,工具链应统一策略 |
HTTP 头与文档声明必须一致。响应已按错误编码解码后,页面内脚本无法可靠修复原始字节。
常见编码¶
| 名称 | Web 状态 | 说明 |
|---|---|---|
| UTF-8 | 推荐 | 覆盖 Unicode,现代 Web 默认选择 |
| UTF-16 | 不用于普通 HTML 传输 | 字节序和兼容性复杂,转换为 UTF-8 |
| GBK / GB2312 | 遗留中文内容 | 浏览器标签映射遵循 Encoding Standard,迁移前识别真实字节 |
| Big5 | 遗留繁体中文内容 | 新内容改用 UTF-8 |
| Shift_JIS | 遗留日文内容 | 新内容改用 UTF-8 |
| windows-1252 | 遗留西文内容 | 常被用于解释历史 iso-8859-1 标签 |
| ISO-8859 系列 | 遗留内容 | 字符范围有限,不适合新多语言页面 |
编码标签的 Web 解析存在历史别名,不应据名称猜测真实算法;以 WHATWG Encoding Standard 为准。
UTF-8 配置清单¶
| 位置 | 建议 |
|---|---|
| 编辑器 | 以 UTF-8 保存源文件,团队统一换行和 BOM 策略 |
| 模板引擎 | 模板、翻译文件和输出流均使用 UTF-8 |
| Web 服务器 | 发送 text/html; charset=utf-8 |
| CSS | 默认跟随传输编码;避免不一致的旧 @charset |
| JavaScript | 以 UTF-8 提供并发送正确 MIME 类型 |
| 数据库 | 使用完整 Unicode 字符集,并检查连接编码 |
| 表单 | 默认按文档编码提交;服务端仍需严格解码验证 |
| URL | 使用 URL 百分号编码规则,不与 HTML 字符引用混淆 |
字符引用¶
| 写法 | 结果 | 用途 |
|---|---|---|
< |
< |
文本中避免被解释为标签开始 |
> |
> |
需要明确表达大于号时 |
& |
& |
避免被解释为字符引用开始 |
" |
" |
双引号属性上下文中常用 |
' |
' |
单引号的数字字符引用 |
😀 |
Unicode 字符 | 十六进制数字字符引用 |
字符引用属于 HTML 语法,不会改变文件编码,也不是跨上下文通用的 XSS 防护。
解码与安全边界¶
- 先把字节按正确编码解码为 Unicode,再进行 HTML、URL、JavaScript 或 CSS 上下文处理。
- 不接受用户任意指定响应编码;编码混淆可能绕过过滤器或产生不同解析结果。
- 服务端、代理、数据库和浏览器对同一数据应使用一致编码,避免二次解码。
- 不通过删除非 ASCII 字符“修复”安全问题;应规范化业务标识并按上下文编码输出。
- Unicode 同形字符、组合字符和双向控制符可能造成显示欺骗,安全标识需额外策略。
无障碍与国际化¶
- 字符编码正确不代表语言声明正确;在
html上设置lang="zh-CN"等语言标签。 - 页面局部切换语言时,在对应元素设置
lang,帮助读屏选择发音规则。 - 不用乱码替代符号、图片文字或私用区字符传递关键信息。
- 表情和符号若承担含义,应提供可理解文本;装饰符号避免造成重复朗读。
- 双向文本使用
dir、bdi等语义机制,不用空格或字符顺序硬凑布局。
乱码排查¶
- 检查原始文件实际字节编码,不只看编辑器状态栏标签。
- 检查 HTTP
Content-Type、meta charset和代理是否一致。 - 检查数据库表、字段、连接和驱动的编码设置。
- 确认数据是否曾被错误解码后再次编码,保留原始字节再修复。
- 用网络面板查看响应字节和头部,不依赖复制后的文本判断。