
PHP 生成的 JSON 在其他语言里解析失败
核心问题往往不是 PHP 生成得不对,而是默认编码或特殊字符没处理干净。PHP 的 json_encode() 默认只保证 UTF-8,但一旦输入字符串本身不是 UTF-8(比如 GBK 数据库读出来的内容),输出就是非法 JSON —— 其他语言如 Python 的 json.loads() 或 JavaScript 的 JSON.parse() 会直接报 UnicodeDecodeError 或 SyntaxError: Unexpected token。
- 用
mb_convert_encoding($data, 'UTF-8', 'GBK')显式转码,别依赖数据库连接层自动转换 - 加
JSON_UNESCAPED_UNICODE参数:json_encode($data, JSON_UNESCAPED_UNICODE),避免中文被转成\u4f60——虽然合法,但增加调试负担,且某些老旧 Java 客户端解析不稳定 - 务必检查
json_last_error(),不要假设json_encode()总是成功;空数组、资源类型、闭包都会让它静默返回false
Python/Java 解析 PHP 输出的 JSON 时字段名对不上
PHP 关联数组(array('user_name' => 'Alice'))序列化后是标准 JSON 对象,但下划线命名习惯和 Java 的驼峰(userName)、Python 的蛇形(user_name)之间没有自动映射 —— 框架不会替你做字段重命名。
- PHP 端主动适配:用
array_change_key_case($data, CASE_LOWER)统一小写,或手动构建键名,比如'user_name' => $row['user_name']改成'userName' => $row['user_name'] - Python 侧不依赖
object_hook做通用转换,容易漏边角 case;建议在反序列化后立刻用字典推导式规整:{to_camel(k): v for k, v in data.items()} - Java 的 Jackson 默认按字段名严格匹配,如果 PHP 发来
user_id,而 Java Bean 写的是userId,必须加@JsonProperty("user_id")注解,不能指望PropertyNamingStrategies.SNAKE_CASE自动生效(它只影响序列化方向)
cURL 返回的 JSON 字符串开头有 BOM 或空白
PHP 脚本文件如果存为 UTF-8 with BOM,或者在 json_encode() 前意外输出了空格、换行(比如模板文件末尾多了一个回车),HTTP 响应体就会以不可见字符开头 —— 导致 Python 的 response.json() 报 JSONDecodeError: Expecting value,Node.js 的 JSON.parse() 报 Unexpected token。
- 确认 PHP 文件保存为 UTF-8 without BOM(编辑器里可设,VS Code 右下角点击编码格式切换)
- 发送前清空输出缓冲:
ob_end_clean();+header('Content-Type: application/json; charset=utf-8');,再echo json_encode(...) - 用
curl -v http://api.example.com直接看响应头和原始 body,比浏览器 Network 面板更可靠;注意检查第一行是不是EF BB BF(BOM 十六进制)
PHP 和 Go 之间时间戳字段类型不一致
PHP 的 date('c') 或 DateTime::ISO8601 输出带时区的字符串(如 "2024-05-20T14:30:00+08:00"),Go 的 time.Time 默认能解析;但 PHP 用 time() 输出整数时间戳,Go 默认不识别 —— json.Unmarshal 会报 cannot unmarshal number into Go struct field X.Time of type time.Time。
立即学习“PHP免费学习笔记(深入)”;
- 统一用字符串格式传输时间,PHP 侧强制:
'created_at' => (new DateTime())->format(DateTime::RFC3339) - Go 侧定义结构体时用字符串字段接收:
CreatedAt string `json:"created_at"`,后续再用time.Parse(time.RFC3339, s.CreatedAt)解析,别依赖time.Time自动反序列化 - 如果必须传时间戳数字,PHP 要确保是 int 类型(
(int)time()),Go 结构体字段声明为int64,并手动转:time.Unix(s.CreatedAt, 0)











