Laravel 5.5 默认不统一 API 返回格式,需手动封装基类控制器提供 success()/error() 方法并重写 Handler::render() 拦截异常,同时确保 API 路由走 api 中间件组且请求头正确,否则前端无法获得可预测的 code 字段。

直接说结论:Laravel 5.5 默认不统一 API 返回格式,response()->json() 只做序列化,不带业务语义;必须手动封装 + 全局异常拦截,否则前端要写 N 套解析逻辑。
基类控制器封装 success()/error() 方法
这是最轻量、最可控的起点。别在每个控制器里手写 response()->json(['data' => $user]),容易漏字段、不一致、难维护。
- 新建
app/Http/Controllers/ApiController.php,继承Controller - 提供
success($data = null, $message = 'success')和error($code = 422, $message = 'fail', $data = [])两个方法,强制返回固定结构:['code' => 200, 'message' => '', 'data' => null] - 所有 API 控制器继承它,比如
class UserController extends ApiController,然后直接用$this->success($user) - 注意:不要覆盖
response()方法本身——5.5 的response()是底层构造器,强行改容易影响文件下载、重定向等非 JSON 场景
重写 Handler::render() 拦截所有异常
这是最容易被跳过的一步。没改这里,ValidationException、ModelNotFoundException、QueryException 全都会跳出你定义的格式,返回裸数组或 HTML 错误页。
- 在
app/Exceptions/Handler.php的render()方法开头加判断:if ($request->expectsJson()) { ... } - 对
ValidationException:提取$exception->errors(),返回422+code: 422+message: '参数校验失败' - 对
ModelNotFoundException:返回404+code: 404+ 中文message(别用默认英文) - 对
AuthenticationException或AuthorizationException:返回401/403,并确保data为空数组,避免前端解构报错
API 路由组 + 请求头识别是关键前提
Laravel 5.5 不会自动识别“这是 API 请求”,靠 Accept: application/json 或 X-Requested-With: XMLHttpRequest 判断。Postman 或安卓端不带这些头,就可能返回 HTML 欢迎页或调试页。
- 在
app/Http/Kernel.php的$middlewareGroups['api']里,确保已启用\Illuminate\Routing\Middleware\SubstituteBindings::class和限流中间件,但**不要**在这里塞 JSON 强制中间件 - 推荐做法:在 API 路由前缀统一加
Accept头,比如用中间件App\Http\Middleware\EnsureJsonAccept,内容为:$request->headers->set('Accept', 'application/json') - 更稳妥的是让客户端主动发
X-Requested-With: XMLHttpRequest——Postman、axios 默认带,安卓 Retrofit 可配置,比依赖 Accept 更可靠 - 切记:别把统一响应中间件挂到
web组,否则POST /login重定向会被 JSON 化,直接炸掉登录流程
别用 ApiResource 替代统一响应格式
ApiResource 是为 JSON:API 规范设计的,在 Laravel 5.5 中默认输出 attributes、relationships 结构,和常见的 data/message/code 完全不兼容。
- 如果你只需要扁平响应(90% 的内部后台接口),ApiResource 是冗余负担,
toArray()里硬塞code字段反而污染资源定义 - 真要用它,只在极少数需对外暴露标准 JSON:API 的接口上启用,其余全部走基类 + 异常处理器方案
-
Resource::collection()对index()有用,但它解决的是数据结构一致性,不是响应契约——code和message还得靠外层包装
真正卡住人的地方,从来不是怎么写 success(),而是 Handler::render() 里忘了加 $request->expectsJson() 判断,或者 API 路由没走 api 中间件组导致异常直接吐 HTML。这两处一漏,前端永远收不到可预测的 code 字段。


















