API响应必须统一为JSON格式,禁用HTML错误页,强制设置Content-Type头,日期统一ISO 8601,CORS需匹配路径并透传OPTIONS请求。

API 返回格式必须统一为 JSON,且禁用 HTML 错误页
Laravel 默认在调试开启时,遇到异常会返回 HTML 页面;生产环境若配置不当,也可能因 APP_DEBUG=true 或中间件拦截逻辑错乱,导致移动端或小程序收到 HTML 内容而非预期的 JSON,直接解析失败。
- 确保
APP_DEBUG=false且APP_ENV=production在生产环境生效 - 全局注册异常处理器,在
app/Exceptions/Handler.php的render()方法中强制返回 JSON:if ($request->expectsJson() || $request->is('api/*')) { return response()->json(['message' => $exception->getMessage()], 500); } - 避免在 API 路由中使用
view()、redirect()或依赖 Session 的中间件(如StartSession)
Content-Type 和字符编码必须显式声明
某些 Android WebView 或旧版 iOS 系统对响应头不敏感,若 Laravel 没有明确设置 Content-Type: application/json; charset=utf-8,客户端可能按 ISO-8859-1 解析中文字段,出现乱码或解析中断。
- 在 API 基础控制器构造函数或中间件中统一添加:
$response->header('Content-Type', 'application/json; charset=utf-8'); - 不要依赖
response()->json()的默认行为——它虽设了Content-Type,但某些自定义响应(如response()->stream())会丢失该头 - 验证方式:用
curl -I https://your.app/api/users查看响应头是否含正确Content-Type
日期格式统一用 ISO 8601,禁用本地化 Carbon 输出
前端(尤其是 JavaScript 的 new Date())和 Flutter 的 DateTime.parse() 仅稳定支持 2024-05-22T14:30:00.000Z 类型字符串;Laravel 默认用 Carbon 的 toDateTimeString() 会输出无时区、无毫秒的 2024-05-22 14:30:00,跨时区下极易出错。
- 在
app/Providers/AppServiceProvider.php的boot()中全局配置:Carbon::serializeUsing(function ($carbon) { return $carbon->toISOString(); }); - 模型中显式指定日期字段访问器:
protected $casts = ['created_at' => 'datetime:Y-m-d\TH:i:s.v\Z'];
- 避免在 API 响应中手动调用
$model->created_at->format(...)—— 容易漏、难维护
跨域(CORS)不能只靠包,要检查预检请求路径匹配
用 fruitcake/laravel-cors 配置后仍出现 404 OPTIONS 或被 Nginx 拦截,常见原因是反向代理未透传 OPTIONS 请求,或 Laravel 路由未覆盖到预检路径(比如 API 前缀是 /v1/,但 CORS 配置只写了 /api/*)。
- 确认
config/cors.php中paths匹配实际路由前缀,例如:'paths' => ['v1/*', 'api/*'],
- Nginx 配置中需显式放行
OPTIONS:if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin "*"; add_header Access-Control-Allow-Methods "GET,POST,OPTIONS,PUT,DELETE"; add_header Access-Control-Allow-Headers "Authorization,Content-Type,X-Requested-With"; add_header Access-Control-Max-Age 86400; add_header Content-Length 0; add_header Content-Type text/plain; return 200; } - 用浏览器开发者工具 Network 标签页,筛选
OPTIONS请求,看是 404(路由没匹配)、403(Nginx 拦截)还是 200 但头缺失(CORS 配置未生效)










