laravel API 返回非标准http状态码需直接设置response()第二参数,但要注意中间件拦截和前端axios的validateStatus默认只将4xx/5xx视为错误;推荐封装apiResponse()统一json结构,区分HTTP状态码与业务码;FormRequest中通过throw HttpResponseException自定义状态码,避免abort或headers已发送错误。

怎么在 Laravel API 里返回非标准 HTTP 状态码
直接改 response() 的第二个参数就行,但得小心框架中间件和前端预期。Laravel 默认会把 200–299 当成成功,400–499 是客户端错误,500–599 是服务端错误——你硬塞个 307 或 422 没问题,但中间件可能拦截、前端 Axios 可能不触发 catch。
-
response('msg', 422)最简单,适合单次响应 - 用
Response::make('msg', 422)也行,本质一样 - 别用
abort(422)来代替——它会走异常流程,触发Handler,日志里多一条记录,还可能被全局render()改写内容 - 如果用了 Sanctum 或 Passport,
401响应会被中间件自动加WWW-Authenticate头,改不了
Laravel API 返回自定义状态码时 JSON 结构怎么统一
状态码变了,但 JSON 格式乱七八糟就难对接。别靠每个控制器手写 return response()->json(['code' => 422, 'msg' => 'xxx']),容易漏字段、错命名。
- 推荐在基类控制器里封装一个
apiResponse()方法,接收$data、$status、$code(业务码)三个参数 - 注意:HTTP 状态码(如
422)和业务码(如'user_not_found')必须分开传,前者控制网络层行为,后者给前端做逻辑分支 - 不要在
AppExceptionsHandler里统一补code字段——异常路径和正常返回路径结构不一致,前端要写两套解析逻辑 - 如果用了
resources,记得在toArray()里不塞 HTTP 状态码,那是响应层的事,不是数据模型的事
API 中间件或表单验证失败时怎么插入手动状态码
FormRequest 验证失败默认返回 422,但有时你需要 400(比如参数缺失)或 403(权限不足却伪装成参数错),不能只靠重写 failedValidation()。
- 在 FormRequest 的
failedValidation()里 throw 新异常,比如throw new HttpResponseException(response()->json(..., 400)) - 别直接
return response()—— Laravel 会报 “headers already sent” 错误,因为验证失败流程已经进入响应准备阶段 - 中间件里想改状态码,用
$next($request)->setStatusCode(403)是无效的;得用return response(..., 403)中断流程 - 如果用了
throttle:api,限流响应固定是429,没法改——这是底层ThrottleRequests写死的,要改就得重写整个中间件
为什么 postman 能收到自定义状态码,但 Axios 却进不到 catch
不是 Laravel 没发出去,是 Axios 默认只把 4xx 和 5xx 当错误,而你返回了 304 或 201 以外的非 2xx 码,它仍当“成功”处理。
- Axios 的
validateStatus默认是status >= 200 && status ,所以 <code>307、422会进then,不是catch - 解决方法:调用时显式配置
validateStatus: status => status 或更细粒度判断 - 别指望 Laravel 后端“让 Axios 自动识别”,状态码语义是双方约定的,前端必须按协议处理
- chrome DevTools 的 Network 面板里看
Status列最准,别光信 console.log 的 response.data
真正麻烦的不是设状态码,而是让所有环节——验证、中间件、资源、异常处理器、前端请求库——对同一个码有共识。一个 422 在表单验证里是参数错,在权限中间件里是拒绝访问,在自定义业务逻辑里可能是库存不足,得靠业务码字段区分,光靠 HTTP 状态码撑不住。