ThinkPHP 6 实现二级域名绑定需通过多应用 domain_bind 配置或 Route::domain() 路由分组;前者彻底隔离应用,后者同应用内路由隔离;必须配对 Nginx Host 透传、hosts 映射及目录结构。

ThinkPHP 6 实现二级域名绑定控制器,关键不在“控制器”本身,而在于**让请求准确落到对应的应用或路由分组中**。框架不支持直接把某个二级域名绑定到单个控制器(如 admin.example.com → app\controller\AdminIndex),而是通过「应用级分发」或「路由层隔离」两条路径实现精准分发。选错路径,轻则404,重则控制器找不到、中间件失效、数据库配置错乱。
一、推荐方案:多应用 + domain_bind 配置(真正隔离)
适用于 admin、api、shop 等需完全独立逻辑、配置、中间件的场景。
- 确保已启用多应用结构:删除根目录
app/controller,用php think build admin创建app/admin/目录 - 在
config/app.php中添加完整域名映射:'domain_bind' => ['admin.example.com' => 'admin', 'api.example.com' => 'api'] - 不要只写
'admin' => 'admin'—— 这是 TP5 的旧写法,TP6 必须是完整域名 - 本地测试时,
domain_bind里必须写'admin.localhost:8000' => 'admin',不能省略端口 - Nginx 需透传 Host 头:
fastcgi_param HTTP_HOST $host;,否则 $_SERVER['HTTP_HOST'] 可能变成 127.0.0.1
二、轻量方案:Route::domain() 路由分组(同应用内隔离)
适用于 user.example.com 和 m.example.com 共享同一套模型、数据库,仅需路由前缀和权限控制不同的情况。
- 先开启域名部署:
'url_domain_deploy' => true(在config/app.php) - 在
route/app.php中注册分组:Route::domain('user', function () { Route::get('profile', 'User/profile'); }); - 该方式下,所有请求仍走默认应用(如
app/),控制器仍在app\controller\下查找 - 若想统一加前缀,可在闭包内调用
Route::group('user', function () { ... }) - 泛域名支持
Route::domain('*', function () { ... }),但不支持Route::domain('*.example.com')
三、避坑要点:常见失效原因
90% 的二级域名 404 或跳转错误,都源于以下几处配置遗漏或冲突:
立即学习“PHP免费学习笔记(深入)”;
- 混淆 domain_bind 和 Route::domain():前者切换应用上下文,后者仅过滤路由;二者不可混用
-
忽略 Nginx Host 头传递:反向代理或 HTTPS 终止后,
$_SERVER['HTTP_HOST']可能被覆盖,必须显式设置fastcgi_param -
本地 hosts 映射不全:测试
admin.example.com时,hosts 文件里必须写127.0.0.1 admin.example.com,不能只写example.com -
APP_SUB_DOMAIN_DEPLOY 已废弃:TP6 不再识别该配置项,启用子域名必须用
url_domain_deploy或domain_bind -
多应用未删除 controller 目录:框架检测到
app/controller存在,会强制进入单应用模式,domain_bind失效
不复杂但容易忽略。配对好 domain_bind、Nginx 和 hosts,再检查一次应用目录结构,二级域名就能稳稳落到你指定的位置。



















