
直接用 response()->json() 最稳妥
Laravel 默认的 JSON 响应走的就是这个函数,它自动设置 Content-Type: application/json、处理数组/对象序列化、兼容中文不乱码。别自己拼 json_encode() + header(),容易漏状态码或 MIME 类型。
常见错误现象:response()->json($data)->status(200) 写成 response()->json($data, 200) —— 后者第二个参数其实是“JSON 选项”,不是 HTTP 状态码;状态码得用 status() 链式调用或传第三个参数。
-
response()->json(['msg' => 'ok'], 200)✅ 正确:第二个参数是状态码(仅当没用status()时才生效) -
response()->json(['msg' => 'ok'], JSON_UNESCAPED_UNICODE)❌ 错误:这会把状态码当成 JSON 选项,返回 500 或空响应 - 如果要加 JSON 选项(比如不转义中文),写成
response()->json($data, 200, [], JSON_UNESCAPED_UNICODE)
自定义结构统一用 API Resource(别在控制器里硬编码)
接口字段经常要隐藏敏感字段、格式化时间、嵌套关联数据——这些逻辑塞进控制器会让代码越来越难维护,也违背 Laravel 的分层原则。
使用场景:用户列表接口要返回 id、name、created_at 格式化为 “Y-m-d H:i”,且不返回 password 和 email_verified_at。
- 运行
php artisan make:resource UserResource - 在
UserResource的toArray()方法里控制输出:return ['id' => $this->id, 'name' => $this->name, 'created_at' => $this->created_at->format('Y-m-d H:i')]; - 控制器里直接
return new UserResource($user);或UserResource::collection($users);
性能影响:Resource 是惰性求值,不会提前触发 N+1 查询;但别在 toArray() 里写 DB 查询,那会破坏它的设计意图。
全局统一响应格式建议封装到基类或中间件,而非每个接口都写
所谓“标准”响应,比如 { "code": 0, "msg": "success", "data": {} },手动在每个接口里包一层,后期改字段名或加字段会疯掉。
容易踩的坑:有人用中间件统一包裹响应,结果把文件下载、重定向、视图响应也给 JSON 化了,导致 PDF 打不开或跳转失效。
- 只对
JsonResponse类型做处理,判断$response instanceof \Illuminate\Http\JsonResponse - 更推荐方式:写一个基控制器方法,比如
success($data = null, $msg = 'success', $code = 0),内部调用response()->json(compact('code', 'msg', 'data')) - 避免在中间件里修改响应体内容,尤其涉及加密、签名等逻辑——它可能被缓存或压缩,顺序难控
ApiResource 和 JsonResource 别混用,Laravel 9+ 已弃用后者
Laravel 9 开始,JsonResource 被标记为废弃,官方文档和源码都指向 ApiResource(即 Illuminate\Http\Resources\Json\JsonResource 的别名)。虽然现在还能用,但升级后会报 E_USER_DEPRECATED。
参数差异很小,但命名和继承路径不同:
- 旧写法:
class UserResource extends JsonResource—— Laravel 8 及以前 - 新写法:
class UserResource extends ApiResource—— Laravel 9+ 推荐,且 IDE 支持更好 - 两者都支持
withoutWrapping()、preserveKeys()等方法,行为一致
兼容性影响:如果你项目还在 Laravel 8,暂时不用急着改;但新项目或准备升级的,直接用 ApiResource 更省心。别等到升级时报一堆 deprecated warning 才回头翻。
真正复杂的是错误响应的统一处理——比如 404、422、500 怎么也套进你的标准结构里,这部分没法靠 Resource 解决,得配合异常渲染器或 render() 方法定制,而且要小心别把框架原生错误信息暴露出去。










