tp6跨域预检失败核心原因是默认不响应options请求,需在中间件中统一通过$response->header()注入cors头,且带credentials时access-control-allow-origin不能为*,必须动态匹配origin白名单并置顶注册中间件。

TP6 跨域预检(OPTIONS)请求报错,核心原因是浏览器在发正式请求前先发一个不带业务参数的 OPTIONS 请求,而 TP6 默认不拦截也不响应它——但中间件仍会执行。若中间件没正确处理这个“空请求”,就容易返回 404、500 或缺失必要响应头,导致前端卡在预检阶段。
确保中间件能覆盖 OPTIONS 请求
TP6 不像 TP5.1 那样自动识别并 exit OPTIONS,所以必须让中间件逻辑对 OPTIONS 也生效。关键不是单独拦截,而是让 $next($request) 正常走完,并在返回的 $response 上统一加头:
- 不要用
if ($request->isOptions()) { return json([]); }这类提前退出写法,容易绕过后续头设置 - 统一走
$response = $next($request);,再对$response注入 CORS 头,这样 OPTIONS 和正常请求都覆盖 - 特别注意:如果中间件里写了
header()或echo,TP6 的响应对象会覆盖它,必须用$response->header()
Access-Control-Allow-Origin 不能为 * + Credentials
前端若设置了 withCredentials: true(比如传 Cookie 或 Authorization),后端就不能写 Access-Control-Allow-Origin: *,否则浏览器直接报错:
- 开发环境可临时设为具体域名,如
https://localhost:3000 - 生产环境建议动态匹配白名单:从
$request->header('Origin')取值,判断是否在允许列表中,再赋给Access-Control-Allow-Origin - 同时必须显式设置
Access-Control-Allow-Credentials: true,缺一不可
检查中间件注册位置和顺序
CORS 中间件必须在路由解析和控制器执行之前运行,否则可能被其他中间件(如鉴权、日志)干扰或跳过:
- 在
app/middleware.php全局中间件数组中,把它放在靠前位置(比如第二位,第一位通常是 TrustedHost) - 如果只对 API 路由启用,要在路由分组里显式绑定:
Route::group('api', function () {...})->middleware(CorsMiddleware::class); - 确认没在某个中间件里调用了
exit或die,这会导致后续中间件(包括 CORS)完全不执行
用 think-cors 扩展省事又稳妥
官方扩展 topthink/think-cors 已适配 TP6 的响应生命周期,能自动处理 OPTIONS 并注入标准头,适合快速上线:
- 安装:
composer require topthink/think-cors - 注册到
app/middleware.php全局中间件数组:\think\middleware\Cors::class - 如需自定义,可在
config/cors.php中配置 origin、credentials、headers 等,比手写更少出错











