ThinkPHP6跨域被拒主因是OPTIONS预检未响应、Access-Control-Allow-Origin与credentials冲突或中间件未生效;须在中间件开头拦截OPTIONS返回204,动态匹配Origin白名单,确保Cors类前置注册且用$response->header()设置头。

ThinkPHP6跨域请求被拒,核心原因通常不是前端发错了,而是后端没在正确时机、用正确方式返回合规的 CORS 响应头。尤其当带 Cookie、Authorization 或自定义 Header(如 X-Auth-Token)时,浏览器会先发 OPTIONS 预检,而 TP6 默认不自动响应它——卡在这一步,后续请求根本不会发出。
检查 OPTIONS 预检是否被正确拦截
浏览器对 POST/PUT/DELETE 或含特定 Header 的请求,必先发 OPTIONS。若控制台显示 OPTIONS 请求 pending、404 或 500,说明预检没被 TP6 处理。
- 确保中间件开头有明确判断:
if ($request->isOptions()) { return response('', 204); } - 返回必须是 204 状态码,响应体为空,且必须包含
Access-Control-Allow-Methods和Access-Control-Allow-Headers - 不要在同一个中间件里既返回 204 又继续执行
$next($request),逻辑冲突会导致失败
确认 Access-Control-Allow-Origin 与 credentials 是否冲突
只要后端设置了 Access-Control-Allow-Credentials: true(即前端用了 credentials: 'include'),Access-Control-Allow-Origin 就绝不能是 *——这是浏览器硬性限制,不是 TP6 问题。
- 必须动态读取请求头:
$origin = $request->header('origin'); - 只对白名单内的域名设置响应头:
if (in_array($origin, ['https://admin.example.com', 'http://localhost:3000'])) { ... } - 同时设置两个头:
'Access-Control-Allow-Origin' => $origin和'Access-Control-Allow-Credentials' => 'true'
验证中间件是否真正生效
写了中间件却没看到 CORS 头,90% 是注册位置或方式不对。
立即学习“PHP免费学习笔记(深入)”;
- 在
app/middleware.php中,\think\middleware\Cors::class必须放在数组靠前位置(建议第 1 或第 2 位),确保它比 Session、JWT、Auth 等中间件更早执行 - 别写成
'cors'或CorsMiddleware::class,官方类名就是\think\middleware\Cors - 多应用模式下,需在对应应用的
app/middleware.php中配置,而非根目录全局文件 - 禁用
header()直接输出——TP6 使用 PSR-7 Response 对象,必须调用$response->header()才有效
核对 Nginx 是否透传 Origin 头
如果 TP6 前还有一层 Nginx,它可能过滤或覆盖了关键请求头,导致后端读不到 Origin。
- 在 Nginx 配置中加入:
proxy_set_header Origin $http_origin; - 同时检查是否重复添加 CORS 头(比如 Nginx 和 PHP 同时设
Access-Control-Allow-Origin),会触发multiple values报错 - 用
curl -I http://yourdomain.com/api/test直接看真实响应头,排除浏览器缓存干扰



















