thinkphp 6 需启用 sub_domain_deploy 并用 route::domain() 显式绑定二级域名,tp5.1 动态绑定需用中间件解析子域名,nginx 必须正确配置 server_name 和 fastcgi_param,多应用与子域名不可混用。

ThinkPHP 6 如何配置二级域名路由绑定
ThinkPHP 6 默认不自动识别二级域名,必须手动开启子域名部署并配置 domain_bind.php 或使用 Route::domain() 显式声明。否则访问 admin.example.com 会直接 404 或落到主站逻辑里。
实操建议:
- 在
config/app.php中确保'sub_domain_deploy' => true已启用 - 在
app/route.php中用Route::domain('admin', function () { ... })定义二级域名专属路由组 - 若用泛域名(如
*.example.com),需配合Route::domain('*', function () { ... }),但注意该写法不兼容所有 Nginx 配置,建议优先用显式绑定 - 二级域名下的控制器命名空间不受影响,仍走默认
app\controller\,但路由前缀可统一加admin/等便于隔离
ThinkPHP 5.1 域名动态绑定的坑与绕过方案
TP5.1 的 domain_bind.php 不支持变量或运行时计算,无法根据数据库查出的商户名动态生成绑定规则(比如 {shop_name}.example.com → ShopController)。硬写死会导致每次新增商户都要改配置、重启服务。
更可行的做法是放弃静态绑定,改用中间件拦截 + 动态解析:
- 关闭
'sub_domain_deploy' => false,让所有请求都进入口 - 写一个
SubDomainParseMiddleware,在$request->host()中提取子域名部分(如strtok($host, '.') === 'shop1') - 将解析出的子域名存入
$request->withParam('sub_domain', $name),后续控制器可直接读取 - 关键点:必须在路由匹配前执行该中间件,所以要放在
app/middleware.php的全局中间件队列最前面
Nginx 下二级域名转发必须加 server_name 通配或显式声明
本地测试时容易忽略 Nginx 配置,导致明明 TP 代码写对了,但 api.example.com 根本进不到 PHP —— Nginx 直接返回 404 或默认站点。
正确配置要点:
- 不要只写
server_name example.com;,必须包含二级域名:server_name example.com www.example.com api.example.com admin.example.com; - 若用泛域名,用
server_name ~^(?<sub>.+)\.example\.com$;</sub>并在fastcgi_param HTTP_HOST $host;后追加fastcgi_param SERVER_NAME $sub;(供 PHP 读取) - 确保
root指向项目 public 目录,且index index.php;存在 - TP 的
$_SERVER['HTTP_HOST']值完全依赖 Nginx 传入,传错或没传,Request::domain()就不可信
多应用模式下二级域名与应用名映射的常见混淆
有人试图把 admin.example.com 直接对应到 app/admin 应用,这是错的。ThinkPHP 的「多应用」和「子域名绑定」是两套机制,混用极易出问题:应用初始化早于域名路由解析,导致 app/admin 的配置根本没加载。
推荐解耦方式:
- 保持单应用结构,用路由分组 + 中间件控制权限和逻辑隔离
- 若真需物理分离,应通过反向代理实现(Nginx 把
admin.example.com转发到另一个独立运行的 TP 实例端口),而非依赖框架内置多应用 -
Route::domain('admin')内定义的控制器仍在主应用目录下,只是路由入口不同,别误以为会自动切换app目录
子域名逻辑越复杂,越要警惕框架自动推导行为。比如 Request::subDomain() 在泛域名场景可能返回空,得自己从 HTTP_HOST 切割;Url::build() 生成链接时不会自动补二级域名,得手动拼接。这些细节不验证,上线后就只能看日志猜了。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











