在php后端开发中,json接口已经成为前后端分离架构下的标准通信方式。无论是app还是网页,基本都通过http请求拿到json字符串再做解析渲染。但实际写代码时,很多人会遇到接口返回数据前端解析失败、本地测试正常线上报错、或者根本拿不到预期字段的问题。这类故障通常不在业务逻辑本身,而在数据格式、响应头和调试手段这三个环节。

一、php中json数据交互的基本写法
php输出json接口最核心的一步是调用json_encode把数组或对象转成字符串,同时用header设置正确的响应类型。如果忘了声明Content-Type: application/json,某些前端框架会按文本处理,导致解析异常。另外json_encode只支持utf8编码,传入gbk中文会直接返回false。
下面是一段最基础的接口输出代码,其中显式关闭了魔术引号并统一了编码:
<?php
header('Content-Type: application/json; charset=utf-8');
// 模拟从数据库取出的数据
$data = array(
'code' => 0,
'msg' => '成功',
'list' => array(
array('id' => 1, 'name' => '测试商品')
)
);
// 注意第二个参数 JSON_UNESCAPED_UNICODE 可避免中文被转成 unicode
$json = json_encode($data, JSON_UNESCAPED_UNICODE);
if ($json === false) {
// 编码失败时给出明确错误
echo json_encode(array('code' => 500, 'msg' => 'json编码失败'));
exit;
}
echo $json;
?>
接收前端json数据时使用file_get_contents('php://input')读取原始报文,再用json_decode解析。很多新手直接用$_POST去接json,结果拿到空数组,因为$_POST只处理表单格式。
以下代码演示了如何稳妥地接收并解析前端发来的json:
<?php
$raw = file_get_contents('php://input');
$input = json_decode($raw, true); // 第二个参数 true 返回数组
if (json_last_error() !== JSON_ERROR_NONE) {
header('Content-Type: application/json; charset=utf-8');
echo json_encode(array('code' => 400, 'msg' => '请求数据不是合法json'));
exit;
}
// 此时 $input 就是可用的关联数组
var_dump($input);
?>
二、常见json接口故障与调试思路
最典型的故障是json_encode返回false。发生这种情况通常有三个原因:数组里混入了gbk字符串、出现了递归引用、或者字段里有不支持的类型比如资源句柄。调试时应当马上用json_last_error和json_last_error_msg打印具体错误,而不是盲目var_dump原数组。
另一个容易被忽略的问题是bom头。如果php文件以utf8 with bom保存,输出json前会先吐出三个字节的bom,前端JSON.parse直接报错。用编辑器转成无bom格式,或在输出前用ob_clean清空缓冲区都能解决。
当接口部署到线上后,浏览器直接访问只能看到渲染后的文字,无法模拟带自定义头的post请求。此时应当使用命令行curl来调试,它可以完整控制方法、头和报文:
# 发送 json 的 post 请求并查看响应头与正文
curl -i -X POST
-H "Content-Type: application/json"
-d '{"user_id":12,"action":"buy"}'
http://127.0.0.1/api/test.php
通过-i参数能看到服务器返回的Content-Type是否正确,响应体是不是纯json。如果线上域名是ipipp.com,把上面地址换成对应站点即可。配合json_last_error在脚本里打点,大部分交互问题都能在十分钟内定位。
三、用日志与工具提升调试效率
除了即时输出,写接口时把关键数据落盘到日志是更稳妥的做法。可以用error_log把解码后的数组、编码前的结构通通记下来,避免频繁改接口影响前端联调。日志内容建议包含时间戳和请求标识,方便对照多次调用。
对于复杂项目,可以引入Postman或Insomnia这类图形化工具,把请求保存为用例,每次只改参数。但在纯php环境下,自己写一个简单的调试路由也很轻量:当检测到特定token时,脚本直接输出json_encode前后的对照数据,不干扰正常业务。
示例调试片段如下,仅在内网调试开启:
<?php
if (isset($_GET['debug']) && $_GET['debug'] === '1') {
header('Content-Type: text/plain; charset=utf-8');
$arr = array('a' => '中文', 'b' => array(1,2,3));
echo "编码前:n";
var_export($arr);
echo "n编码后:n";
echo json_encode($arr, JSON_UNESCAPED_UNICODE);
echo "n错误码: " . json_last_error();
exit;
}
?>
这种写法把编码结果和错误码并列展示,比反复改前端更快。等接口稳定后,删掉debug分支或加上ip白名单即可。
四、小结
php调试json接口的核心在于明确数据在编码、传输、解码三个阶段各自的约束。写接口时主动设响应头、用json_last_error兜底;接数据时放弃$_POST改用原始输入流;排查故障优先上curl和日志而不是靠肉眼比对。把这些方法固定成自己的开发习惯,json交互中的绝大多数坑都能在本地被提前填平。