ThinkPHP二级域名绑定与跨域需协同配置:先用前置中间件校验Host白名单并拦截非法请求,再动态匹配Origin设置Access-Control-Allow-Origin和Credentials,同时Nginx透传HTTP_ORIGIN头,并确保中间件注册顺序在Session/Auth之前。

ThinkPHP 配置二级域名绑定后,既要确保请求正确路由到对应应用或模块,又要解决跨域问题(尤其带 Cookie 的场景),不能只靠单一配置。核心在于:中间件必须同时承担域名识别拦截和CORS 动态响应两项职责,且执行顺序、预检处理、凭据兼容性三者缺一不可。
一、先做域名识别与非法访问拦截
二级域名绑定本身不等于安全控制。即使 Route::domain() 已配置 admin.example.com → admin 应用,攻击者仍可伪造 Host 头直连服务器。必须用中间件在路由前校验域名合法性:
- 创建中间件:
php think make:middleware CheckSubDomain - 在
handle()开头读取真实 Host:$host = $request->header('host') ?: $request->host();(兼容代理) - 白名单建议从配置文件读取:
config('domain.whitelist'),内容如['admin.example.com', 'api.example.com', 'localhost:8000'] - 不匹配时立即返回:
return response('Forbidden', 403);,避免后续流程执行 - 该中间件必须放在
app/middleware.php全局数组最前面,确保早于路由解析
二、再配动态 CORS 响应(支持 credentials)
前端若设置了 credentials: 'include',后端就不能用 Access-Control-Allow-Origin: *,否则浏览器直接拒绝。必须根据当前请求的 Origin 动态匹配并返回:
- 在同一个中间件(或独立 CorsMiddleware)中,获取 Origin:
$origin = $request->header('origin'); - 检查是否在白名单内:
in_array($origin, config('cors.allow_origins')),白名单需包含所有合法前端地址(含协议+端口) - 匹配成功才设置:
$response->header('Access-Control-Allow-Origin', $origin); - 必须同步设置:
$response->header('Access-Control-Allow-Credentials', 'true'); - 对 OPTIONS 请求提前响应:
if ($request->isOptions()) { return response('', 204); },防止 405 错误
三、Nginx 层必须透传关键头信息
很多跨域失败其实卡在 Nginx,不是 PHP 代码问题。以下三项必须显式配置:
立即学习“PHP免费学习笔记(深入)”;
-
server_name要覆盖所有二级域名,例如:server_name ~^(?<sub>.+)\.example\.com$;</sub>或逐条写死admin.example.com api.example.com - 确保
fastcgi_param HTTP_ORIGIN $http_origin;已添加,否则 PHP 拿不到 Origin 头 - 若使用 CDN 或反向代理,还需透传
X-Forwarded-Host和X-Forwarded-Proto,并在中间件中做兼容判断
四、路由绑定与中间件协同要点
Route::domain() 是路由层能力,中间件是请求层能力,二者要配合才能闭环:
- 开启子域名部署:
'url_domain_deploy' => true(TP6 正确配置项,非旧版sub_domain_deploy) - 在
route/app.php中显式绑定:Route::domain('admin', function () { ... })->append(['app' => 'admin']); - 若用多应用模式(app/admin/ 目录),
Route::domain('admin', 'admin')可直接映射应用,但中间件仍需全局注册,不能只放某应用 middleware.php 中 - 中间件注册顺序:CheckSubDomain 和 CorsMiddleware 必须排在 Session、Auth 等中间件之前,否则凭据未校验就已响应



















