应封装全局助手函数 api_result(),因其比 json() 函数更可控:能统一设置 http 状态码与 code 字段、强制 data 类型安全、注入默认 msg、避免格式不一致,并支持单元测试。

直接封装一个全局助手函数最稳妥,比基类方法或中间件更可控、无侵入、易测试。
为什么不能只靠 json() 函数
ThinkPHP 的 json() 是快捷函数,它内部调用 response()->json()->send() 并立即终止脚本,不支持链式设置状态码;你传 ['code'=>400] 进去,HTTP 状态码仍是 200 —— 前端用 response.status 判断会误判。另外,json() 不校验数据结构,data 字段可能被漏写或类型错(比如传了字符串而非数组),导致前端解析崩溃。
- 必须显式控制 HTTP 状态码时,得用
response()->json($data)->code($code),且顺序不能反 -
json()无法统一注入msg默认值或做空data安全兜底 - 不同控制器里反复写
return json(['code'=>..., 'msg'=>..., 'data'=>...]),字段名大小写、空格、默认值稍有不一致,就埋下前后端联调隐患
推荐封装 api_result() 助手函数
在 app/common.php(或 app/helper.php,确保已开启自动加载)里定义:
function api_result($data = null, $code = 200, $msg = 'ok') {
// 强制 data 为数组或 null,避免前端 JSON.parse 报错
if ($data !== null && !is_array($data) && !is_object($data)) {
$data = (string) $data;
}
$result = [
'code' => (int) $code,
'msg' => (string) $msg,
'data' => $data ?? []
];
return response()->json($result)->code($code);
}
- 所有接口统一用
return api_result($user);或return api_result(null, 400, '参数缺失'); - 返回结构强约束:即使传了字符串
$data,也转成字符串值,不会让data字段变成数字或布尔导致前端解析失败 - 状态码与 JSON body 中的
code字段保持一致,避免前后端对“成功”定义不一致 - 不依赖控制器继承关系,不污染基类,单元测试时可直接 require 后调用
别踩这些坑
封装后仍可能出问题,关键在调用上下文:
- 在中间件中提前输出过内容(比如
echo ''、var_dump()、甚至文件末尾多了一个空格),会导致headers already sent,response()->json()失效,返回空白或原始 PHP 错误 - 如果用了
default_return_type => 'json'全局配置,控制器return ['code'=>200]会自动转 JSON,但此时状态码固定为 200,无法动态设 401/500 —— 与封装的api_result()冲突,建议关掉这个配置 - 在命令行环境(如
php think run)下,response()不真正发送 header,但 JSON body 仍正常,此时应以code字段为准,不要依赖curl -I查状态码 - 若需兼容小程序或老版安卓 WebView,注意
JSON_UNESCAPED_UNICODE选项,可在response()->json()第二个参数传入:response()->json(..., JSON_UNESCAPED_UNICODE)->code(...)
最复杂的地方其实不在封装本身,而在于——是否所有团队成员都放弃手写 json_encode() 和 echo,哪怕只是临时调试也走 api_result()。一旦有人绕过,格式一致性就断了。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











