应使用 response()->json() 统一返回 JSON,显式传入状态码(如 201、204、404、422、403),配置 JSON_UNESCAPED_UNICODE 等选项,封装统一响应结构,并兜底处理验证失败、模型未找到等异常。

直接用 response()->json() 就行,别拼 json_encode() + header(),也别裸写数组返回——看似省事,实际容易丢状态码、乱码、跨域失败或被中间件劫持。
状态码必须显式传,别靠默认
HTTP 状态码不是可选配置,它决定前端是否触发 success 或 error 分支。Laravel 默认返回 200,但创建资源该用 201,删除成功该用 204(注意:204 不允许带响应体),查不到数据是 404,参数错是 422,权限不足是 403。
-
response()->json(['data' => $user], 201)✅ 创建成功 -
response()->json(['message' => 'Deleted'], 204)✅ 删除成功(空响应体) -
response()->json(['error' => 'Not found'], 404)✅ 资源不存在 -
response()->json(['errors' => $validator->errors()], 422)✅ 验证失败
JSON 选项要配对,中文不转义得手动开
默认 JSON 编码会把中文转成 \uXXXX,前端看着费劲。加 JSON_UNESCAPED_UNICODE 就能保留原样,但它不是第二个参数——很多人误写成 response()->json($data, JSON_UNESCAPED_UNICODE),结果状态码被当成 JSON 选项,响应直接崩。
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
- 正确写法:
response()->json($data, 200, [], JSON_UNESCAPED_UNICODE) - 常见组合:
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES(防斜杠转义) - 空数组别强制对象:
JSON_FORCE_OBJECT会让[]变成{},前端Array.isArray()判定失效
结构统一靠封装,别在控制器里硬写
每个接口都手写 ['code' => 0, 'msg' => '', 'data' => []],字段名不一致、缺字段、漏状态码,后期改起来全是坑。推荐两种轻量级做法:
- 在
AppServiceProvider::boot()里注册响应宏:Response::macro('api', function ($data = null, $code = 200, $message = null) {<br> return response()->json([<br> 'code' => $code,<br> 'message' => $message ?: Response::$statusText[$code] ?? 'OK',<br> 'data' => $data<br> ], $code);<br>});
控制器中直接return response()->api($user, 200, 'success'); - 基类控制器加方法:
protected function success($data = null, $message = 'success') { return response()->json([...], 200); }
异常和验证失败也要走同一套结构
控制器返回了标准格式,但验证失败抛出的 422、模型找不到的 404、PHP 错误的 500,如果还是 HTML 或原始异常堆栈,前端就收不到 code 和 message。
- 验证失败:重写
FormRequest::failedValidation(),throw new HttpResponseException(response()->api([], 422, 'validation failed')); - 模型未找到:在
app/Exceptions/Handler.php的render()中捕获ModelNotFoundException,返回response()->api([], 404, 'not found') - 全局错误:同上,捕获
Throwable,生产环境只返回简洁 message,不开 debug
不复杂但容易忽略——状态码、编码选项、结构封装、异常兜底,四点齐了,API 才算真正稳住。

















