API错误响应必须统一用response()->json()返回JSON,禁用throw异常和abort();自定义异常需在Handler.php中判断expectsJson();验证失败应覆写failedValidation();状态码须准确对应错误类型;错误结构应复用Laravel内置标准。

API错误响应必须用response()统一返回,别直接throw异常
Laravel默认把未捕获异常转成HTML页面,API里这会直接崩掉前端解析。你写的throw new ValidationException或abort(404),在API路由里会返回HTML,而不是JSON——前端拿到一堆<!DOCTYPE html>就懵了。
实操建议:
- 所有API控制器方法,结尾统一走
response()->json(),哪怕只是response()->json(['message' => 'ok'], 200) - 别依赖
abort(),它在api中间件组下仍可能返回HTML;改用return response()->json(['message' => 'Not Found'], 404) - 自定义异常(比如
InvalidInputException)要在app/Exceptions/Handler.php里重写render(),对$request->expectsJson()返回response()->json()
Laravel 10+ 的validate()自动抛错不兼容API?得关掉ThrowValidationException
新版Laravel在FormRequest里默认启用ThrowValidationException,一验证失败就抛ValidationException,而这个异常的渲染逻辑是为Web设计的——它塞了errors进view,API里根本用不上。
实操建议:
- 在
app/Http/Requests/YourRequest.php里,加public function rules(): array后,手动调用$this->validator($data)->validate(),跳过自动抛错流程 - 或者更干脆:在
FormRequest里覆写failedValidation(),改成throw new HttpResponseException(response()->json([...], 422)) - 注意
validated()方法只在验证通过后才可用,别在rules()或messages()里调它
状态码不能全用200,4xx/5xx必须真实反映问题类型
很多新手图省事,所有错误都返回200 OK加个success: false字段。这会让前端无法用HTTP状态码做路由判断(比如Axios的response.status === 401跳登录),也破坏REST语义。
实操建议:
-
400 Bad Request:参数缺失、格式错误(如email字段传了数字) -
401 Unauthorized:Token无效或过期,别和403混用 -
403 Forbidden:Token有效但没权限(比如普通用户访问管理员接口) -
422 Unprocessable Entity:仅用于表单验证失败,Laravel默认用这个,别手贱改成400 -
500 Internal Server Error:真出错了才用,别拿它当兜底;数据库连接失败、Redis超时这些要单独捕获并返回更具体的码(比如503 Service Unavailable)
错误结构别自己发明,用Laravel内置的Illuminate\Http\Exceptions\ThrottleRequestsException这类现成逻辑
有人喜欢写['error' => ['code' => 'INVALID_TOKEN', 'message' => 'xxx']],结果每个地方字段名不一致,前端要写N个解析分支。其实Laravel大部分异常已经自带标准化JSON输出逻辑,只是默认没启用。
实操建议:
- 速率限制错误(
ThrottleRequestsException)默认返回429+ JSON,但字段是message和retry_after,别额外包一层error对象 - 认证失败(
AuthenticationException)在Handler.php里检查$exception instanceof AuthenticationException,直接return response()->json(['message' => 'Unauthenticated.'], 401) - 别给所有错误加
trace字段——开发环境可以开APP_DEBUG=true看堆栈,生产环境必须关掉,否则泄露路径和类名
最麻烦的其实是前端怎么区分「服务端逻辑错误」和「网络错误」,HTTP状态码+统一message字段是最小成本方案。字段命名、嵌套层级、是否带errors明细,这些细节一旦上线就很难改,一开始就得定死。










