thinkphp 6.0 跨域需路由级显式配置 allowcrossdomain() 并满足三条件:仅限 http 路由链式调用、带括号、带 cookie 时首参须为明确域名数组且次参为 true;全局中间件 cors 与 allowcrossdomain 行为不同,应手动编写中间件拦截 options 并动态设置响应头,nginx 仅处理预检,避免头重复。

allowCrossDomain() 只对显式 HTTP 路由生效,且完全不管 OPTIONS 预检;直接在控制器里写 header() 或返回带头的 JSON 基本无效——响应对象会被后续流程覆盖。
路由级跨域怎么配才真正生效
->allowCrossDomain() 不是开关,是给单条路由挂一个轻量中间件,必须满足三个硬条件:
- 只能用在
Route::get()、Route::post()等显式 HTTP 路由定义之后,不能写在闭包里或 console/event 路由中 - 必须链式调用且带括号:
->allowCrossDomain(),漏掉()就完全不注册 - 若前端带 Cookie(
credentials: 'include'),第二个参数必须为true,且第一个参数不能含*,得是明确域名数组:->allowCrossDomain(['https://admin.example.com', 'http://localhost:3000'], true)
->allowCrossDomain() 不传参,看似 OK;一上生产配了 withCredentials: true,浏览器立刻静默拒绝——因为后端发了 Access-Control-Allow-Origin: * + Access-Control-Allow-Credentials: true,这组组合被 CORS 协议明令禁止。
全局中间件为什么写了没反应
think\middleware\Cors::class 和 think\middleware\AllowCrossDomain::class 行为完全不同,混用必翻车:
-
think\middleware\Cors::class(TP6.1+ 内置)只加响应头,**不拦截 OPTIONS**,预检失败时仍会卡住 -
think\middleware\AllowCrossDomain::class(TP6.0.x 内置)只设Access-Control-Allow-Origin,其他头如Allow-Headers一概不管
app/middleware/Cors.php 中:
开头判断 $request->isOptions(),直接 return response('', 204);
之后调 $next($request),再对 $response 调 header() 设置全部字段;
顺序不能错:header() 必须在 return $response 前,且不能在 $next() 前设——否则头被丢弃。
带 Cookie 的请求为什么总被浏览器忽略
不是后端没发头,是发了错的头:- 只要启用了凭证(
credentials: 'include'),Access-Control-Allow-Origin就不能是*,必须和请求头Origin完全一致(协议、域名、端口全匹配) -
Access-Control-Allow-Credentials必须设为'true'(字符串,不是布尔值) -
Access-Control-Allow-Headers必须显式列出前端实际发送的字段,比如前端发了X-Auth-Token,这里就得写'X-Auth-Token',大小写敏感,漏一个就预检失败
if ($origin = $request->header('origin')) {
$allowed = ['https://admin.example.com', 'https://app.example.com'];
if (in_array($origin, $allowed)) {
$response->header('Access-Control-Allow-Origin', $origin);
$response->header('Access-Control-Allow-Credentials', 'true');
}
}
Nginx 层要不要加 CORS 头
要,但只能加在 OPTIONS 预检上,业务响应头必须交给 PHP:- 删掉 Nginx 配置里所有
add_header Access-Control-Allow-Origin类指令,否则和 PHP 层重复,触发浏览器报错The 'Access-Control-Allow-Origin' header contains multiple values - 在
server块里加预检拦截:if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin https://admin.example.com; add_header Access-Control-Allow-Methods GET, POST, PUT, DELETE, OPTIONS; add_header Access-Control-Allow-Headers Content-Type, Authorization, X-Requested-With, X-Auth-Token; add_header Access-Control-Allow-Credentials true; add_header Access-Control-Max-Age 86400; return 204; }
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











