统一响应格式需在handler::render()兜底异常、api路由限定routes/api.php、控制器用基类/宏封装,禁用全局json中间件,严格区分状态码语义并避免双重编码。

直接用 response()->json() 能返回 JSON,但“统一响应格式”不是加个函数调用就完事——它不处理异常、不校验请求类型、不控制状态码语义,前端拿到的仍是 200 里套 data、422 里套 errors、404 返回 HTML 的混乱结构。
API 响应必须区分请求类型,不能靠全局中间件硬塞 JSON
很多人在 app/Http/Kernel.php 的全局中间件里写 header('Content-Type: application/json'),结果把 POST /login 重定向、GET /storage/report.pdf 全干成 JSON 报错。真正安全的做法是:
- API 路由只注册在
routes/api.php(它默认启用api中间件组,含 JSON 协商逻辑) - 手动测试时加头:
curl -H "Accept: application/json" http://localhost:8000/api/user - 中间件内别用
response()->json()包一层——会覆盖原始状态码;正确做法是复用$response实例:$response->setContent(...)->withHeaders(...) - 务必先判断
$response->content()是否已是 JSON,避免json_encode(json_encode())双重编码
验证失败、模型未找到、500 错误必须在 Handler::render() 统一兜底
这些异常根本不会进控制器,response()->json() 在那里压根碰不到。不改 app/Exceptions/Handler.php 的 render(),前端就会收到裸 HTML 或空响应体。
- 加判断:开头写
if ($request->expectsJson()) { ... },用$request->is('api/*')作备选 -
ValidationException:提取$exception->errors(),返回code: 422、message: '参数校验失败'、data: [] -
ModelNotFoundException:别用默认英文提示,手动返回code: 404+ 中文message - 其他未捕获异常(如数据库连接失败):fallback 到标准结构,否则前端收不到
code字段
控制器里别手写 response()->json(),优先用基类封装或响应宏
碎片化写法导致字段不一致、状态码错乱。比如创建资源后仍返回 200 而非 201,违反 REST 规范。
- 新建
app/Http/Controllers/ApiController.php,继承Controller,提供success()、error()、fail()方法,强制输出code、message、data三字段 - 或在
AppServiceProvider::boot()中定义响应宏:Response::macro('success', function ($data = [], $code = 200) { return response()->json(['code' => $code, 'message' => 'OK', 'data' => $data], $code); }); - 注意状态码语义:
201用于创建成功(带 body),204用于删除成功(无 body,别传数组) - 分页响应别直接
$users->toJson()——会丢meta字段;要用$users->toArray()后手动补全
最易被忽略的是:异常可能发生在路由匹配前、中间件执行前、视图渲染时——这些地方中间件根本没机会运行,唯一能覆盖全部路径的只有 Handler::render()。漏掉它,任何封装都只是局部补丁。











