PHP API 返回乱码最常见原因是未设置 Content-Type header 或缺失 charset=utf-8,导致浏览器默认按 ISO-8859-1 解析;须在输出前调用 header('Content-Type: application/json; charset=utf-8'),并确保输入为 UTF-8。

PHP API 返回乱码,90% 是 header 没设对
不是文件编码问题,也不是数据库连接编码没设好——最常见、最直接的原因是响应头缺失 Content-Type 或未声明字符集。浏览器(或调用方)收到无 charset 的 JSON 响应时,默认按 ISO-8859-1 解析,中文立刻变 。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 必须在输出任何内容前调用
header('Content-Type: application/json; charset=utf-8'); - 确保该
header()在echo、json_encode()或任何输出语句之前执行 - 检查是否有 BOM 头、空格、调试
var_dump()或echo提前触发了输出缓冲(会令header()失效) - 用
headers_sent()快速验证:如果返回true,说明 header 已无法设置
json_encode() 输出乱码?先确认输入字符串本身是 UTF-8
json_encode() 只接受 UTF-8 编码的字符串。如果从数据库、文件或 POST 数据中拿到的是 GBK、GBK2312 或其他编码,直接传进去就会出 或空字符串(PHP 7.2+ 默认返回 false)。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 查来源:MySQL 连接需设
charset=utf8mb4(注意是utf8mb4,不是utf8),PDO DSN 加;charset=utf8mb4,mysqli 用set_charset('utf8mb4') - 不信任外部输入:对非 UTF-8 字符串做转换,例如
mb_convert_encoding($str, 'UTF-8', 'GBK') - 加容错:用
json_last_error()判断编码失败,避免静默返回空 - 慎用
JSON_UNESCAPED_UNICODE—— 它只影响中文是否被 \uXXXX 转义,不解决底层编码问题
Apache / Nginx 配置不会导致 API 乱码,但可能掩盖 header 问题
Web 服务器的默认字符集(如 Apache 的 AddDefaultCharset)只影响纯文本响应,对设置了 Content-Type 的响应无效。但它可能干扰调试:比如你忘了设 header,服务器自动加了 charset=ISO-8859-1,反而让你误以为是服务端问题。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- Nginx 中不要配
charset utf-8;全局指令,它会覆盖 PHP 的header() - Apache 中禁用
AddDefaultCharset,或至少确保它不作用于application/json类型 - 用
curl -I http://your-api.com/endpoint直接看响应头,确认Content-Type是否含charset=utf-8
测试时 curl 和 Postman 显示正常 ≠ 前端 JS 正常
curl 和 Postman 默认按响应头解析,而前端 fetch() 或 XMLHttpRequest 在 Content-Type 缺失 charset 时,可能因浏览器策略降级为 Latin-1;更隐蔽的是,某些 Vue/Axios 封装会自动调用 response.json(),但若底层响应体实际是乱码字节,解析仍会失败。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 在浏览器开发者工具 Network → Response 标签页里,右键「Open in new tab」看原始响应 —— 如果显示乱码,说明问题在服务端输出
- 用
new TextDecoder('utf-8').decode(new Uint8Array(response.arrayBuffer))手动解码测试响应体原始字节 - 后端加日志:把
json_encode()后的字符串bin2hex()截取前 32 位,确认是否为合法 UTF-8 字节序列(如中文“你好”应以e4bda0开头)
Accept: application/json 不影响响应编码,真正卡住的永远是服务端那行漏掉的 header() 和那一串没转对的字节。











