必须将HandleCors中间件置于$middleware数组首项,配置cors.php的paths包含上传路径、allowed_origins明确指定域名且supports_credentials设为true,并在Nginx中透传OPTIONS请求并返回204响应。

前端通过 fetch 或 axios 向 Laravel 后端上传文件时被浏览器拦截,提示“Access to XMLHttpRequest at 'http://api.example.com/upload' from origin 'http://localhost:3000' has been blocked by CORS policy”,说明跨域策略未覆盖文件上传路径或凭证配置冲突,必须同步处理 OPTIONS 预检、响应头、Nginx 转发与 supports_credentials 四个关键层。
确认并启用 HandleCors 中间件
打开 app/Http/Kernel.php 文件,检查 $middleware 数组顶部是否已存在 \Fruitcake\Cors\HandleCors::class。若缺失或位于底部,Laravel 无法在请求生命周期早期拦截预检请求——此时即使 config/cors.php 写对了也完全不生效。
将该中间件【必须置于 $middleware 数组第一项】,不要放在 $middlewareGroups['api'] 里,因为文件上传接口常走 /upload 这类非 api/* 路径,而 $middlewareGroups['api'] 只作用于显式套了 middleware('api') 的路由。
执行 php artisan config:clear 清除配置缓存,避免旧配置残留干扰。
配置 cors.php 允许上传路径与凭证
运行 php artisan vendor:publish --tag="cors" 确保 config/cors.php 存在。编辑该文件,重点修改以下三项:
paths:必须包含文件上传路由路径,例如 ['api/*', 'upload', 'upload/*', 'sanctum/csrf-cookie']。只写 ['api/*'] 会导致 /upload 请求被直接拒绝。
allowed_origins:若前端携带 Cookie(如 Sanctum 登录态),【supports_credentials 必须为 true,且 allowed_origins 绝不能是 ['*']】。开发环境写成 ['http://localhost:3000', 'http://127.0.0.1:3000'];生产环境必须明确列出所有前端域名,如 ['https://app.example.com', 'https://admin.example.com']。
supports_credentials:设为 true,否则浏览器不会发送 Cookie,后端无法校验登录态,文件上传接口会返回 401。
验证 Nginx 是否透传 OPTIONS 请求
浏览器上传文件前必发 OPTIONS 预检请求。若 Nginx 拦截并返回 405 或 404,Laravel 根本收不到该请求,HandleCors 中间件永不执行。
在 Nginx server 块中添加以下配置:
location / {
# 允许跨域请求头
add_header 'Access-Control-Allow-Origin' '$http_origin' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
# 处理预检请求
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 17280000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
}
重启 Nginx:sudo systemctl restart nginx。这一步不做,所有 PHP 层配置都白搭。
测试上传接口是否真正放行
第一步:用 curl 发送 OPTIONS 预检请求,验证响应头是否完整:
curl -X OPTIONS -H "Origin: http://localhost:3000" -H "Access-Control-Request-Method: POST" -I http://your-laravel-app.test/upload
观察返回头中是否有 Access-Control-Allow-Origin: http://localhost:3000 和 Access-Control-Allow-Credentials: true。
第二步:前端发起真实上传请求,fetch 配置必须带 credentials: 'include',否则 Cookie 不发出,后端无法识别用户身份。
第三步:检查 Laravel 日志 storage/logs/laravel.log,若看到 OPTIONS /upload 请求记录,说明 Nginx 已转发且中间件已执行;若无此记录,问题仍在 Nginx 层。


















