统一响应需拦截所有api响应路径:注册于routes/api.php,覆盖正常返回、验证失败(422)、模型未找到(404)、500错误四类场景,强制状态码(如201/204),过滤敏感异常信息。

直接用 response()->json() 就能返回 json,但“统一响应格式”不是加个包装函数就完事——关键在于拦截所有 API 响应、处理异常、并确保状态码和结构一致。
API 路由必须明确指定 Accept: application/json
laravel 的 response()->json() 本身不强制要求请求头,但统一响应逻辑常依赖 Request::isJson() 或中间件判断是否为 API 请求。如果前端没带 Accept: application/json(比如用浏览器直接访问路由),Laravel 可能走视图渲染流程,导致返回 HTML 而非 JSON。
- API 路由务必注册在
routes/api.php中(该文件默认自带api中间件组,含EnsureFrontendRequestsAreStateful和自动 JSON 检测) - 手动测试时用
curl -H "Accept: application/json" http://localhost:8000/api/user,避免被重定向或返回视图 - 不要依赖
Route::middleware('api')单独套在web.php路由上——它不会自动启用 JSON 响应协商
统一响应需覆盖正常返回、验证失败、模型未找到、500 错误四类场景
只改控制器里的 return response()->json([...]) 是碎片化处理。真正统一要靠 Laravel 的全局响应机制:
- 正常响应:在基控制器中封装
success()方法,但更推荐使用响应宏(Response::macro('success', ...)),在AppServiceProvider::boot()中定义 - 验证失败:重写
FormRequest::failedValidation(),抛出HttpResponseException并包裹response()->json(..., 422) - 模型未找到(404):在
app/Exceptions/Handler.php的render()方法中检测$exception instanceof ModelNotFoundException,返回response()->json(['message' => 'Not found'], 404) - 500 错误:同样在
Handler::render()中捕获Throwable,开发环境可保留详情,生产环境只返回['message' => 'Server Error']和 500 状态码
response()->json() 的第三个参数容易被忽略
这个参数是 HTTP 状态码,默认是 200。但很多开发者写成 response()->json(['data' => $user]),结果创建资源后仍返回 200 而非 201,违反 REST 规范。
- 创建成功用
response()->json(['data' => $user], 201) - 删除成功用
response()->json(['message' => 'Deleted'], 204)(注意:204 不允许带响应体,所以别传数组) - 分页响应建议用
LengthAwarePaginator+toArray(),再手动补全meta字段,不要直接$users->toJson()—— 它会丢掉分页元信息 - 避免在 JSON 中嵌套原始 sql 错误(如
SQLSTATE[23000]),生产环境必须过滤$exception->getMessage()
最难的不是写一个 ApiResponse 类,而是让所有异常路径、隐式模型绑定、表单验证、甚至队列任务失败回调,都流经同一套 JSON 响应出口。漏掉任意一环,前端就会收到 500 HTML 页面或空响应体。