ThinkPHP跨域问题需服务端正确返回CORS响应头并处理OPTIONS预检请求,推荐路由级allowCrossDomain()、自定义CorsMiddleware中间件或Nginx层add_header三类方案,注意凭据支持、Origin动态匹配及常见失效排查。

ThinkPHP部署后出现CORS跨域问题,核心是服务端未在HTTP响应中正确返回浏览器认可的跨域头,且未妥善响应OPTIONS预检请求。生产环境不能依赖开发阶段的临时写法,必须确保响应头稳定、时机准确、策略安全。
路由级精准开放(适合API接口)
只对实际需要跨域的接口生效,不影响后台、命令行等其他路由,最轻量也最可控。
- 在 route/app.php 中定义 HTTP 路由时,链式调用
->allowCrossDomain(),例如:Route::post('api/login', 'Api/Login@login')->allowCrossDomain(['https://admin.example.com', 'http://localhost:3000'], true); - 启用凭据(如 Cookie 或 Authorization)时,第一个参数必须是明确域名数组,绝不能含 *;第二个参数设为
true才会添加Access-Control-Allow-Credentials: true - 确认该路由属于
HTTP类型——console、event、rpc路由不支持此方法
自定义Cors中间件(推荐用于全站或动态校验)
这是TP6/8生产环境最稳定的方式,能统一拦截OPTIONS、动态匹配Origin、避免响应头被覆盖。
- 执行命令生成中间件:
php think make:middleware CorsMiddleware - 编辑 app/middleware/CorsMiddleware.php,在
handle()开头拦截 OPTIONS:if ($request->isOptions()) { return response('', 204); } - 在
$response = $next($request)后设置响应头,注意顺序:$response->header('Access-Control-Allow-Origin', $request->header('origin') ?: 'https://your-frontend.com');$response->header('Access-Control-Allow-Credentials', 'true');$response->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');$response->header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With'); - 将
\app\middleware\CorsMiddleware::class添加到 app/middleware.php 的数组首位,确保最早执行、最晚结束
Nginx层兜底配置(适合无法改代码或需CDN兼容)
当PHP层配置受限(如共享主机、Swoole环境),或需与CDN/反向代理协同时,直接在Web服务器层注入响应头更可靠。
立即学习“PHP免费学习笔记(深入)”;
- 在对应 server 或 location 块中添加:
add_header 'Access-Control-Allow-Origin' 'https://your-frontend.com' always;add_header 'Access-Control-Allow-Credentials' 'true' always;add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With' always; - 必须加
always参数,否则Nginx默认不给 204/4xx 响应加头,导致OPTIONS失败 - 若需支持多个前端域名,可配合
map指令动态匹配 Origin,避免硬编码 - 确保 Nginx 透传原始
Origin头:不使用proxy_set_header Origin ""类清空操作
常见失效原因排查
很多配置看似写了却无效,往往卡在细节上:
-
OPTIONS 返回 405:检查
app/config/app.php中'method_filter' => false,或把OPTIONS加入白名单数组 -
带 Cookie 请求失败:前后端必须同步——前端 fetch 配
credentials: 'include',后端不能设Access-Control-Allow-Origin: *,且 session 配置中'domain'要匹配主域(如'.example.com') -
响应头没生效:用
curl -X OPTIONS -I http://yoursite.com/api/test直接看真实响应头,绕过浏览器缓存和界面干扰 -
中间件不执行:确认它注册在
app/middleware.php数组首位,且类路径完全正确(含命名空间)



















