Laravel CORS中间件生效核心在于三点:必须将HandleCors置于$middleware顶部(紧接TrustProxies后),supports_credentials为true时allowed_origins禁用['*'],且Nginx需透传OPTIONS请求并返回204。

用中间件处理 Laravel 的 CORS 跨域,核心不是“加一个中间件”就完事,而是确保它在正确位置运行、配置不自相矛盾、且能扛住 OPTIONS 预检。Laravel 9.2+ 已内置 \Illuminate\Http\Middleware\HandleCors,老版本(如 Laravel 8 及以下)用 \Fruitcake\Cors\HandleCors,逻辑完全一致。
中间件必须挂对位置才能生效
它不能只塞进 $middlewareGroups['api'] 里——那样只管显式加了 middleware('api') 的路由。如果你的接口是直接 Route::get('/api/data', ...) 定义的,没套任何中间件组,那 CORS 中间件根本不会执行。
- 全局生效:把
\Illuminate\Http\Middleware\HandleCors::class(Laravel 9.2+)或\Fruitcake\Cors\HandleCors::class(Laravel 8-)加到$middleware数组顶部,紧接在\App\Http\Middleware\TrustProxies::class后面 - API 路由专用:确保它出现在
$middlewareGroups['api']中,且靠前——别被auth:sanctum或StartSession挡住 - 别塞到底部、别塞进
web组里当摆设、也别只写在$routeMiddleware却忘了在路由上实际调用
allowed_origins 和 supports_credentials 别硬碰硬
浏览器强制规定:只要启用了凭据(supports_credentials => true,对应前端 fetch(..., { credentials: 'include' })),allowed_origins 就绝不能是 ['*']。否则直接报错 A wildcard '*' cannot be used,连预检都过不去。
- 开发环境写死:比如
['http://localhost:3000', 'http://127.0.0.1:3000'];http://localhost:*不合法,端口不支持通配 - 生产环境必须收敛:只列可信域名,例如
['https://app.example.com', 'https://admin.example.com']
- 如果不需要传 Cookie 或 token,可设
'supports_credentials' => false,此时allowed_origins才能放心用['*']
OPTIONS 预检请求得真能走通
Laravel 不自动注册 OPTIONS 路由,预检失败往往不是 CORS 配置错,而是中间件链提前返回了 405 或 401。
- 确认目标路径在
config/cors.php的'paths'里,例如['api/*', 'sanctum/csrf-cookie'] - 检查该路由没被
auth:sanctum、auth:api等认证中间件包裹——预检请求不带 token,认证中间件会直接拒掉 - Nginx 层要透传 OPTIONS:加
if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"; add_header Access-Control-Allow-Headers "Content-Type, Authorization"; add_header Access-Control-Allow-Credentials "true"; return 200; }
调试时别只盯一个响应头
一个完整的跨域响应至少要凑齐三项:Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Credentials(如果需要凭据)。少一个,前端照样报错,而且浏览器控制台通常只提示第一个失败项。
- 用浏览器开发者工具的 Network 面板,点开失败请求 → Headers → Response,逐个核对这三个头是否存在、值是否匹配
- 用
curl -I -X OPTIONS http://your-api.com/api/data直接测预检响应,排除前端干扰 - 执行
php artisan route:list看目标路由是否真的绑定了 CORS 中间件











