laravel api 响应需手动统一格式:通过 apicontroller 封装 success/error 方法、api 中间件精准生效、handler::render() 兜底异常,并配合 apiresource 控制字段,否则前端将面对混乱的 status/code/data 结构。

直接返回数组或模型,Laravel 默认会转成 JSON 并设 Content-Type: application/json,但「统一格式」这件事框架不帮你做——你得自己封装结构、拦截异常、区分请求类型,否则前端早晚被 200 里套 data、422 里套 errors、404 返回 HTML 这些混乱响应搞崩溃。
response()->json() 是基础,但不能靠它统一格式
它只负责序列化+设头,不带业务语义。比如:
-
response()->json(['user' => $user])和response()->json(['message' => '参数错误'], 422)字段不一致,前端要写两套解析逻辑 - 模型直接
return $user会走自动 JSON 化,但字段控制(如隐藏password)还得靠$hidden或资源类 - 它不处理验证失败、模型未找到等异常——这些压根不会进控制器,
response()->json()根本碰不到
API 响应必须区分请求类型,不能全局挂中间件
很多人在 app/Http/Kernel.php 的全局中间件里硬塞 Content-Type: application/json,结果把 POST /login 重定向、GET /storage/report.pdf 文件下载全干成 JSON 报错。
- 只对 API 路由生效:用
Route::prefix('api/v1')->middleware('api.response')->group() - 中间件内别用
response()->json()包一层,会丢原始状态码和 header;正确做法是复用$response实例:$response->setContent(...)+$response->withHeaders(...) - 务必先判断
$response->content()是否已是 JSON,避免json_encode(json_encode(...))双重编码
异常必须在 Handler::render() 里统一兜底
没改这里,ValidationException、ModelNotFoundException、QueryException 全部跳出你的格式——它们根本不会经过控制器或中间件。
- 在
app/Exceptions/Handler.php的render()方法开头加判断:if ($request->expectsJson()) { ... } -
ValidationException:提取$exception->errors(),返回code: 422、message: '参数校验失败'、data: [] -
ModelNotFoundException:别用默认英文提示,手动返回code: 404+ 中文message - 其他未捕获异常(如数据库连接失败),也得 fallback 到标准结构,否则前端收不到
code字段
控制器里优先用基类封装,而不是手写 response()
新建 app/Http/Controllers/ApiController.php,继承 Controller,提供 success()、error()、fail() 方法,强制输出 code、message、data 三字段。
- 所有 API 控制器继承它,比如
class UserController extends ApiController -
$this->success($user)内部调用response()->json(),但确保结构固定 - 别在方法里写
return ['data' => $user]—— 这种写法绕过封装,且异常时完全不生效 - 配合
ApiResource控制模型输出字段,比在模型里反复写toArray()更可控
最常被跳过的其实是异常处理器里的 render() 重写——只要漏掉这一块,哪怕控制器封装再漂亮,前端收到的 422、404 依然不是你定义的格式。











