Laravel中API路由带查询字符串导致CORS请求失败问题
问题场景
使用Laravel 10 + Sanctum做后端身份认证,Next.js做前端,部分GET请求正常,但带查询字符串的请求触发CORS错误:
Access to XMLHttpRequest at 'https://api.example.com/api/threads/single/thread_ID/?type=image-messages' from origin 'https://www.example.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
当前config/cors.php配置:
<?php return [ 'paths' => ['api/*', 'sanctum/csrf-cookie', 'login', 'logout'], 'allowed_methods' => ['*'], 'allowed_origins' => ['*'], 'allowed_origins_patterns' => [], 'allowed_headers' => ['*'], 'exposed_headers' => [], 'max_age' => 0, 'supports_credentials' => true, ];
核心疑问:明明配置了api/*匹配所有API路径,为什么带查询字符串会触发CORS错误?
问题根源
问题不在查询字符串本身,而在于URL末尾的斜杠+查询字符串的组合:
Laravel默认会自动将带末尾斜杠的URL重定向到不带斜杠的版本(比如/api/threads/single/thread_ID/?type=image-messages会被重定向到/api/threads/single/thread_ID?type=image-messages)。而CORS预请求(OPTIONS请求)的规则不允许响应是重定向,浏览器直接拦截了这个不符合规则的响应,导致报错。
你尝试的api/threads/single/*{?}*路径配置无效,是因为Laravel的CORS路径匹配使用Str::is方法,只匹配URL的路径部分,不包含查询字符串,这种写法不属于支持的通配符规则。
解决方案
方案1:去掉URL末尾的斜杠(最直接)
修改前端请求URL,删除路径末尾的斜杠:
- 错误写法:
https://api.example.com/api/threads/single/thread_ID/?type=image-messages - 正确写法:
https://api.example.com/api/threads/single/thread_ID?type=image-messages
这样可以避免Laravel触发自动重定向,预请求能正常通过CORS校验。
方案2:禁用Laravel的末尾斜杠重定向
如果需要保留末尾斜杠的URL格式,可以关闭Laravel的自动重定向功能:
在app/Providers/RouteServiceProvider.php的boot方法中添加一行代码:
public function boot() { $this->configureRateLimiting(); $this->routes(function () { Route::middleware('api') ->prefix('api') ->group(base_path('routes/api.php')); Route::middleware('web') ->group(base_path('routes/web.php')); }); // 关闭末尾斜杠自动重定向 \Illuminate\Support\Facades\URL::withoutTrailingSlash(); }
或者在config/app.php中添加/修改配置项:
'trailing_slash' => false,
方案3:调整CORS路径匹配(可选)
如果不想修改URL或关闭重定向,可以尝试在cors.php的paths中添加带末尾斜杠的路径规则:
'paths' => ['api/*', 'api/*/', 'sanctum/csrf-cookie', 'login', 'logout'],
不过这种方式不如前两种可靠,因为需要覆盖所有可能带末尾斜杠的API路径。
内容的提问来源于stack exchange,提问作者Skykid Felix

