你是不是也遇到过这种报错👇
json_decode(): Malformed UTF-8 characters, possibly incorrectly encoded
或者:
json_decode(): Syntax error, unexpected 'extra data'
接口明明返回了内容,
就是解析不了。
先说结论一句话:
90% 的 JSON 解码失败,不是 JSON 写错,是“编码 / 返回内容不干净”。
下面我们一步一步来。
一、最常见的 2 种报错,到底是什么意思?
① malformed UTF-8 characters
直译:字符串里有“非法 UTF-8 字符”
常见原因只有几个:
- 接口返回 GBK / GB2312
- 数据里混了中文 + 非 UTF-8
- 字符串前后带 BOM
- 从文件 / 数据库读出来就已经是脏数据
② extra data
意思是:
👉 JSON 是对的,但后面还多了东西
比如接口实际返回的是:
{"code":0,"msg":"ok"}<br />
或者:
{"data":123}
{"debug":"xxx"}
JSON 只能解析一份干净数据,
后面多一个字节都不行。
二、第一步:永远先把“原始返回”打出来
新手最容易犯的错是:
直接 json_decode,不看原始内容
你一定要先这样:
$response = curl_exec($ch);
var_dump($response);
exit;
你会惊讶地发现👇
- 看似 JSON,其实前面有空格
- 后面多了一行 HTML 报错
- 中文全是乱码
三、malformed UTF-8 的 6 种真实原因
1️⃣ 接口不是 UTF-8
国内老接口常见:
- GBK
- GB2312
解决:
$response = mb_convert_encoding($response, 'UTF-8', 'GBK');
2️⃣ UTF-8 + BOM(隐形杀手)
字符串开头有三个字节:
EF BB BF
处理方式:
$response = preg_replace('/^\xEF\xBB\xBF/', '', $response);
3️⃣ 数据库本身不是 UTF-8
- 表是 utf8
- 字段是 latin1
👉 读出来就炸。
4️⃣ 文件内容编码不对
file_get_contents() 读的文件不是 UTF-8,
直接解码必报错。
5️⃣ 字符串里混了不可见字符
比如:
- 控制符
- 非法二进制
可以先做清洗:
$response = iconv('UTF-8', 'UTF-8//IGNORE', $response);
6️⃣ PHP 源文件本身有 BOM
你以为是接口问题,
其实是 PHP 文件保存格式错了。
四、extra data 的 5 种高频场景
1️⃣ 接口输出了 HTML
- Notice
- Warning
- Debug echo
✔ 关闭错误输出,查日志。
2️⃣ 后端多 echo 了一句
echo json_encode($data);
echo "success";
👉 必炸。
3️⃣ 多次 json_encode
返回了两段 JSON。
4️⃣ gzip 没解压
看起来是乱码,其实是压缩内容。
curl_setopt($ch, CURLOPT_ENCODING, '');
5️⃣ 接口前后有空格 / 换行
有些严格环境也会报错。
五、万能 JSON 解码安全写法(直接用)
$response = trim($response);
// 去 BOM
$response = preg_replace('/^\xEF\xBB\xBF/', '', $response);
// 强制转 UTF-8
$response = mb_convert_encoding($response, 'UTF-8', 'UTF-8,GBK,GB2312,ISO-8859-1');
$data = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
echo json_last_error_msg();
var_dump($response);
exit;
}
👉 这段代码能解决 80% 的 JSON 解码失败。
六、快速自检清单(收藏级)
你可以按顺序问自己:
- 原始返回我看了吗?
- 编码是不是 UTF-8?
- 有没有 BOM?
- 有没有多余输出?
- gzip 解了吗?
- 是不是接口本身在报错?