乱码主因是编码声明、文件实际编码、HTTP响应头三者不一致;需确保Content-Type为text/html; charset=utf-8,位于最前且无BOM,文件真实编码为UTF-8。

乱码不是编码没写,而是编码声明、文件实际编码、HTTP响应头三者不一致。只要其中一环错位,中文就大概率变方块或问号。
为什么写了还是乱码
这个标签只在 HTTP 响应头没带 charset 时才起作用;一旦服务器返回了 Content-Type: text/html; charset=gbk,浏览器直接按 GBK 解析, 彻底失效。
- 用 Chrome 按
F12→Network→ 刷新 → 点 HTML 请求 → 查Response Headers中的Content-Type值 -
Content-Type必须是text/html; charset=utf-8(注意连字符和小写) - 如果看到
iso-8859-1或gbk,问题出在 Web 服务器或后端代码,不是 HTML 文件本身 -
必须出现在最开头,前面不能有任何空格、换行、注释或 BOM 字节
VS Code 保存后还是乱码的真正原因
VS Code 右下角显示 “UTF-8”,不代表文件真是 UTF-8 —— 它可能只是“以 UTF-8 解释当前字节”,而文件实际是 GBK 编码存的。你看到的“中文”其实是 VS Code 把 GBK 字节强行当 UTF-8 解出来的假象。
- 打开文件后,点击右下角编码名称 → 选
Reopen with Encoding→ 依次试GBK、UTF-8、ISO-8859-1,看哪一种能正常显示中文且无乱码 - 确认真实编码后,再点右下角 →
Save with Encoding→ 选UTF-8(**不要选 “UTF-8 with BOM”**) - Linux/macOS 下用
file -i filename.html查真实编码;Windows 下可用PowerShell执行Get-Content -Encoding UTF8 -Raw filename.html | Out-Null测试是否报错 - 若输出含
EF BB BF(用xxd -l 3 filename.html查),说明有 BOM,必须删掉再存
Node.js / PHP / Nginx 返回 HTML 时乱码
后端不显式设 Content-Type 头,就会继承服务器默认值(Nginx 默认 iso-8859-1,PHP 内置服务器也一样),跟 HTML 里写多少 meta 都无关。
- Node.js(原生):
res.setHeader('Content-Type', 'text/html; charset=utf-8'),必须在res.end()前调用 - Express:
res.set('Content-Type', 'text/html; charset=utf-8')或res.sendFile(path, { headers: { 'Content-Type': 'text/html; charset=utf-8' } }) - PHP:
header('Content-Type: text/html; charset=utf-8');必须在任何输出(包括空格、前空白)之前调用 - Nginx:在
location块加add_header Content-Type "text/html; charset=utf-8";;注意别和charset utf-8;同时用,会冲突
本地双击打开(file://)时乱码
此时没有 HTTP 响应头,浏览器只认 ,但对位置极其敏感 —— 它必须是 内第一个可解析的标签,前面不能有任何不可见字符。
- 用十六进制编辑器(如 HxD、
xxd)检查文件开头 3 字节:要是ef bb bf,就是 BOM,删掉 - 确保
是里的第一行,前面没空格、没注释、没空行 - 不要用 Windows 记事本保存 HTML —— 它默认存为 ANSI(即 GBK)或 UTF-8 with BOM,两者都踩坑
- 如果仍不行,临时加个
放在前面(仅作 fallback,非推荐)
BOM 和响应头缺失是最隐蔽的两个点:一个藏在文件开头看不见,一个藏在网络请求里看不到。不查这两处,光改 meta 标签等于在修漏水的屋顶却不管破裂的水管。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











