核心是「文件实际编码」「HTML声明」「HTTP响应头」三者严格一致;任一错位即触发系统默认编码(如GBK),导致中文显示为ä¸Â等乱码,须逐层验证BOM、meta位置、响应头及缓存。

乱码不是“换种编码试试”就能解决的,核心是让「文件实际编码」「HTML声明」「HTTP响应头」三者严格一致。只要其中一环错位,浏览器就会 fallback 到系统默认编码(Windows 下通常是 GBK),中文立刻变成 丠或 鐢ㄦ埛 这类组合。
检查 <meta charset> 是否在 <head> 最前面且写法正确
这个标签必须是 <head> 内第一个非空白、非注释的子元素,且只允许出现一次。浏览器只扫描前 1024 字节,任何前置内容(包括 BOM、空格、注释、<!DOCTYPE html> 后的换行)都可能导致它被跳过。
- 错误写法:
<meta charset="utf8">、<meta charset="UTF8">、<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">—— HTML5 只认utf-8(小写、带连字符) - 正确位置示例:
<head> <meta charset="utf-8"> <title>我的页面</title> </head>
- 如果用了模板引擎(如 EJS、Thymeleaf),确认生成后的 HTML 源码里它确实出现在
<head>开头,而不是被动态插入到中间
验证 HTML 文件是否真为 UTF-8(无 BOM)编码保存
编辑器显示“UTF-8”不等于文件就是 UTF-8。VS Code 默认在 Windows 上保存为 UTF-8 with BOM,而 BOM(ef bb bf)会卡在 <meta charset> 前面,直接让它失效。
- VS Code:右下角点击编码标识 → “Save with Encoding” → 选
UTF-8(明确避开UTF-8 with BOM) - 命令行验证(Linux/macOS):
head -c 4 yourfile.html | xxd,输出含ef bb bf就说明有 BOM,需清除后重存 - Windows PowerShell 验证:
Get-Content yourfile.html -Encoding Byte | Select -First 3,若前三字节是239, 187, 191,即 BOM - Notepad++:菜单栏“编码” → “转为 UTF-8 编码”(不是“UTF-8-BOM”)
确认 HTTP 响应头中的 Content-Type 没有覆盖或冲突
当页面通过 http:// 或 https:// 访问时,服务器返回的 Content-Type 响应头优先级高于 <meta charset>。哪怕 HTML 里写对了,头里是 charset=gbk 或压根没声明 charset,照样乱码。
立即学习“前端免费学习笔记(深入)”;
- 浏览器 F12 → Network → 刷新 → 找主 HTML 请求 → Headers → Response Headers → 查看
Content-Type值 - Nginx 配置中避免写
charset iso-8859-1;或漏掉charset utf-8;;正确写法是charset utf-8;(全局)或add_header Content-Type "text/html; charset=utf-8";(慎用,可能重复) - Node.js/Express:必须在
res.send()前调用res.set("Content-Type", "text/html; charset=utf-8") - PHP:必须在任何输出(包括空格、BOM)之前调用
header("Content-Type: text/html; charset=utf-8")
排除浏览器缓存和本地干扰
即使服务端全对,浏览器也可能缓存了旧版本(含错误响应头或旧 HTML),或者扩展程序篡改了页面内容。
- 先用无痕窗口打开,若正常,说明问题出在当前浏览器环境
- 停用所有扩展,尤其翻译、广告拦截、脚本注入类插件
- 清理该站点的缓存、Cookie 和存储(Settings → Privacy → Cookies and other site data → Search → 输入域名 → Remove)
- 强制刷新(Ctrl+Shift+R 或 Cmd+Shift+R),绕过内存缓存
- 不要用
file://协议双击打开 HTML —— 此时无 HTTP 头,完全依赖<meta charset>,但 BOM 或位置错误仍会失效
最容易被忽略的是:BOM 和响应头的双重失效。一个文件带 BOM,同时 Nginx 又返回了 charset=iso-8859-1,这时候无论怎么改 <meta> 都没用。必须逐层验证,不能只盯着 HTML 源码改。



















