ThinkPHP API 接口统一返回格式需分层拦截与全局兜底:重写Json响应类output方法强制包装结构,中间件兜底非Json响应,基类封装调用重写类,配置default_return_type和路由分组强化一致性。

ThinkPHP API 接口返回格式统一,不能只靠写一个 json() 或封装个 success 方法就完事——因为不同路径(正常返回、验证失败、异常抛出、模型报错)会绕过你的封装,最终输出五花八门的结构。真正落地要分层拦截、全局兜底。
重写 Json 响应类,接管所有 return json()
直接修改 think\response\Json 类的 output($data) 方法,把原始数据强制包进标准结构:
- 返回数组固定为:
['code' => $this->code, 'msg' => $this->message, 'data' => $data] - 不改构造逻辑,只动输出环节,兼容原有调用方式(如
json($data, 201)仍生效) - 注意:
$this->code和$this->message默认来自 Response 实例属性,可在控制器中提前设好,例如$this->result = ['code'=>400, 'msg'=>'参数错误']; return json($data);
中间件兜底非 Json 响应
很多错误场景(如验证失败、未捕获异常、空 return)不会走 Json 类,而是生成普通 think\Response 实例或纯数组。在全局中间件里统一识别并转换:
- 判断
$response instanceof \think\Response且不是Json实例 - 若响应体是数组(如验证器默认返回),尝试提取
['code', 'msg', 'data']字段;缺失则补默认值 - 若响应体是字符串或其他类型,一律包装为:
['code' => 500, 'msg' => 'server error', 'data' => null] - 中间件需放在响应发送前最后执行(如配置在
app/middleware.php的末尾)
基类封装 success/error,但必须走重写后的通道
在 BaseController 中定义 success($data, $msg = 'ok') 和 error($msg, $code = 400) 是常见做法,但关键在于底层调用:
立即学习“PHP免费学习笔记(深入)”;
- 不能直接
return json([...]),而要调用你重写的 Json 类,例如:return (new \think\response\Json($data))->code($code)->message($msg); - 或者复用中间件兜底机制,确保即使误用
return ['code'=>...]也能被标准化 - 避免在 Trait 或助手函数里用原生
json_encode()或echo,否则彻底脱离框架响应链
配置 default_return_type + 路由分组强化一致性
在 config/app.php 中设 'default_return_type' => 'json',让所有控制器 return 数组自动转 JSON,再配合路由分组隔离 API 流量:
- API 路由单独分组(如
Route::group('api', function () {...})),避免和后台 HTML 页面混用同一套响应逻辑 - 该配置下,
return ['code'=>200, 'msg'=>'ok', 'data'=>$user]会自动走 Json 响应流程,前提是没被其他中间件提前终止 - 搭配中间件兜底后,哪怕某处忘了写
json(),也能被拉回标准轨道



















