字符编码(UTF-8)
字符编码决定了计算机如何将字符(如汉字、英文字母、标点符号)转换为二进制数据。在 Web 开发中,UTF-8 已经成为统一的标准编码,支持全球几乎所有语言和符号。本节将详细介绍 UTF-8 编码声明、BOM(字节顺序标记)、编码检测机制,以及常见乱码问题的排查方法。
前置知识
阅读本节前,建议先了解:lang 属性与语言声明
为什么需要字符编码
计算机只能处理二进制数据,字符编码提供了字符与二进制之间的映射规则。不同的编码方案支持不同的字符集:
| 编码 | 支持语言 | 说明 |
|---|---|---|
| UTF-8 | 所有语言 | 变长编码(1-4 字节),向后兼容 ASCII |
| UTF-16 | 所有语言 | 固定 2/4 字节,Windows 内部常用 |
| UTF-32 | 所有语言 | 固定 4 字节,处理方便但空间浪费 |
| GBK/GB2312 | 简体中文 | 中国国家标准 |
| Big5 | 繁体中文 | 台湾地区常用 |
| Shift_JIS | 日语 | 日本常用 |
| EUC-KR | 韩语 | 韩国常用 |
| ISO-8859-1 | 西欧语言 | Latin-1,不支持中文 |
统一使用 UTF-8
现代 Web 开发应统一使用 UTF-8 编码,避免使用 GBK、Big5 等地区性编码。UTF-8 支持全球所有语言,且是 HTML5 规范的推荐编码。
UTF-8 声明
HTML5 标准声明
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<!-- UTF-8 声明:必须在 <head> 前 1024 字节内 -->
<meta charset="UTF-8" />
<title>字符编码示例</title>
</head>
<body>
<p>中文、日本語、한국어、English、Français</p>
</body>
</html>为什么 charset 要在 head 开头
- 浏览器在解析 HTML 时,需要尽早知道字符编码
- 如果在遇到
<meta charset>之前遇到了非 ASCII 字符,可能使用错误的编码解析 <meta charset>应尽量出现在<head>的前 1024 字节内
HTML4 时代的方式(已过时)
html
<!-- HTML4 方式:已不推荐 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />HTTP 头声明
服务器也可以通过 HTTP 响应头声明编码:
Content-Type: text/html; charset=UTF-8编码优先级:HTTP 头 > HTML meta 标签 > BOM
BOM(字节顺序标记)
BOM(Byte Order Mark)是 UTF-8/16/32 编码文件开头的特殊标记字节。
| 编码 | BOM 十六进制 | 说明 |
|---|---|---|
| UTF-8 | EF BB BF | 可选,表示 UTF-8 |
| UTF-16 (BE) | FE FF | 大端序 |
| UTF-16 (LE) | FF FE | 小端序 |
| UTF-32 (BE) | 00 00 FE FF | 大端序 |
| UTF-32 (LE) | FF FE 00 00 | 小端序 |
Web 开发与 BOM
html
<!-- UTF-8 文件带 BOM:文件开头有 EF BB BF 三个字节 -->
<!-- 浏览器通常能正确处理,但可能导致问题 -->
<!-- 问题 1:PHP 的 header() 函数前有 BOM 会报错 -->
<?php
header('Location: /home');
// 如果文件带 BOM,这个 header() 调用会失败
// 因为 BOM 的字节会被当作输出
?>
<!-- 问题 2:JavaScript 文件带 BOM 可能引起解析错误 -->
// UTF-8 BOM 会作为文件的第一个字符
// 在严格模式下可能导致问题
<!-- 问题 3:CSS @charset 规则前有 BOM 会被忽略 -->
@charset "UTF-8";
/* 如果文件带 BOM,@charset 不生效 */建议:Web 文件不使用 BOM
HTML、CSS、JavaScript 文件建议保存为 UTF-8 without BOM(无 BOM 的 UTF-8),以避免潜在问题。
乱码问题排查
常见乱码原因
| 原因 | 症状 | 解决方法 |
|---|---|---|
| 文件实际编码与声明不一致 | 中文显示为 ??? 或 å�ä» | 统一使用 UTF-8 保存和声明 |
| 数据库编码不一致 | 从数据库读取的数据乱码 | 数据库连接和表都使用 UTF-8 |
| HTTP 头与 meta 不一致 | 部分内容乱码 | 确保服务器发送正确的 Content-Type |
| 文件带 BOM | 页面开头出现  | 以 UTF-8 without BOM 保存 |
| URL 编码问题 | 查询参数中文乱码 | 使用 encodeURIComponent |
排查步骤
html
<!-- 1. 检查 HTML 声明 -->
<head>
<meta charset="UTF-8" /> <!-- 确保有此声明 -->
</head>
<!-- 2. 检查 HTTP 响应头 -->
<!-- Chrome DevTools → Network → Response Headers -->
<!-- Content-Type: text/html; charset=UTF-8 -->
<!-- 3. 检查文件实际编码 -->
<!-- VS Code:右下角状态栏查看编码 -->
<!-- Sublime Text:File → Reopen with Encoding -->
<!-- 4. 检查数据库连接 -->
<!-- PHP:mysqli_set_charset($conn, "utf8mb4") -->
<!-- Node.js:使用 utf8mb4 字符集 -->数据库编码
sql
-- MySQL 设置数据库和表为 UTF-8
CREATE DATABASE myapp
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL
) CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;php
// PHP 连接数据库设置编码
$mysqli = new mysqli('localhost', 'user', 'pass', 'myapp');
$mysqli->set_charset('utf8mb4');
// 或者使用 PDO
$pdo = new PDO('mysql:host=localhost;dbname=myapp;charset=utf8mb4', 'user', 'pass');特殊字符处理
HTML 实体
html
<!-- 必须转义的字符 -->
< <!-- 小于号 < -->
> <!-- 大于号 > -->
& <!-- 和号 & -->
" <!-- 双引号 " -->
' <!-- 单引号 '(HTML5 中可用) -->
<!-- 示例 -->
<p>使用 <div> 标签创建容器</p>
<p>价格:5 & 10 元</p>Unicode 字符引用
html
<!-- 十进制引用 -->
<p>版权所有 © 2024</p>
<p>人民币 ¥¥100</p>
<!-- 十六进制引用 -->
<p>版权所有 © 2024</p>
<!-- 命名实体 -->
<p>版权所有 © 2024</p>
<p>注册商标 ®</p>
<p>省略号 …</p>
<p>破折号 —</p>Emoji 表情
UTF-8 天然支持 Emoji:
html
<!-- Emoji 在 HTML 中直接使用 -->
<p>前端开发 🚀 太有趣了!</p>
<p>学习进度:💯 100%</p>
<!-- 也可以直接使用 Unicode 字符 -->
<p>前端开发 🚀 太有趣了!</p>
<p>学习进度:💯 100%</p>实战示例:多语言 UTF-8 页面
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>UTF-8 多语言页面</title>
<style>
body {
font-family: "PingFang SC", "Microsoft YaHei", "Noto Sans SC", sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 2rem;
}
.lang-section { margin: 2rem 0; padding: 1rem; border: 1px solid #e0e0e0; border-radius: 8px; }
.lang-section h2 { margin-top: 0; }
</style>
</head>
<body>
<h1>UTF-8 编码支持示例</h1>
<p>本页面使用 UTF-8 编码,可以正确显示以下所有语言:</p>
<div class="lang-section">
<h2>简体中文</h2>
<p>春眠不觉晓,处处闻啼鸟。夜来风雨声,花落知多少。</p>
</div>
<div class="lang-section" lang="zh-Hant">
<h2>繁體中文</h2>
<p>春眠不覺曉,處處聞啼鳥。夜來風雨聲,花落知多少。</p>
</div>
<div class="lang-section" lang="ja">
<h2>日本語</h2>
<p>春眠暁を覚えず、処処啼鳥を聞く。夜来風雨の声、花落知多少。</p>
</div>
<div class="lang-section" lang="ko">
<h2>한국어</h2>
<p>HTML5는 현대 웹 개발의 핵심 기술입니다.</p>
</div>
<div class="lang-section" lang="en">
<h2>English</h2>
<p>HTML5 is the core technology for modern web development.</p>
</div>
<div class="lang-section" lang="fr">
<h2>Français</h2>
<p>HTML5 est la technologie de base du développement Web moderne.</p>
</div>
<div class="lang-section" lang="de">
<h2>Deutsch</h2>
<p>HTML5 ist die Kerntechnologie für die moderne Webentwicklung.</p>
</div>
<div class="lang-section">
<h2>特殊字符</h2>
<p>
版权 © | 注册 ® | 商标 ™ | 省略号 … |
箭头 → | 乘号 × | 除号 ÷ |
人民币 ¥ | 欧元 € | 磅 £
</p>
</div>
<div class="lang-section">
<h2>Emoji 表情符号</h2>
<p>
😀 😎 🚀 💻 📱
🎨 🌍 ☂ ☕ 🎵
</p>
</div>
</body>
</html>注意事项
- 统一使用 UTF-8:所有文件(HTML、CSS、JS、数据库)都使用 UTF-8 编码
- 不带 BOM 保存:Web 文件以 UTF-8 without BOM 保存
- 尽早声明编码:
<meta charset="UTF-8">放在<head>最前面 - 数据库使用 utf8mb4:MySQL 的
utf8只支持最多 3 字节的 UTF-8,utf8mb4支持完整的 4 字节(包括 Emoji) - HTTP 头也要正确:确保服务器发送
Content-Type: text/html; charset=UTF-8
最佳实践
- 编辑器默认编码设为 UTF-8 without BOM
- 所有新文件保存为 UTF-8
<meta charset="UTF-8">放在<head>的第一行- 数据库使用
utf8mb4字符集 - API 请求和响应都使用 UTF-8
- 处理用户输入时验证编码合法性
- 使用 Content-Security-Policy 防止编码注入
下一节
继续学习:文本方向(dir 属性)