ThinkPHP5不支持域名绑定子目录模块,模块是逻辑划分而非物理路径;Route::domain()第二参数只能是闭包或数组,不能为字符串;启用域名绑定需同时满足开启url_domain_deploy、路由定义在route/app.php、Web服务器指向public目录三条件。

ThinkPHP5不支持“域名绑定子目录模块”这种说法——它没有子目录模块的概念,只有模块(module),而模块路径和URL结构是解耦的。所谓“绑定到子目录”,其实是误把Web服务器的目录映射当成了框架行为。
为什么 Route::domain('m.example.com', 'mobile') 不等于“绑定到 public/mobile 目录”
ThinkPHP5 的模块是逻辑划分,不是物理目录映射。mobile 是一个模块名,对应 application/mobile/ 目录(非 public/mobile)。public 下永远只放入口文件(如 index.php),所有请求都经由它统一调度。
- 写
Route::domain('m.example.com', 'mobile')后,访问m.example.com/index/index实际调用的是application/mobile/controller/Index.php中的index方法 - 如果在 Nginx/Apache 里把
m.example.com指向public/mobile,框架根本收不到请求——直接 403 或 404,因为那里没有入口文件 - 本地开发时若用
php -S启动,也必须确保路由入口(public/index.php)是唯一 Web 根目录,不能切到子目录
正确启用域名绑定的三步硬性条件
缺一不可,漏掉任意一条都会导致 Route::domain() 完全不生效。
- 在
application/config.php中开启:'url_domain_deploy' => true - 域名路由定义必须写在
route/app.php(不是route/route.php,也不是config/route.php) - 确保 DNS 或 hosts 已解析该域名,并且 Web 服务器(Nginx/Apache)已将该域名指向项目
public/目录(不是子目录)
Route::domain() 第二个参数只能是闭包或数组,不能是字符串
这是最常翻车的点:很多人照着“绑定到模块”的描述,直接写成 Route::domain('m.example.com', 'mobile'),结果报错 Invalid route rule。
立即学习“PHP免费学习笔记(深入)”;
- ✅ 正确写法(闭包):
Route::domain('m.example.com', function () { Route::get('/', 'index/index'); Route::get('user/:id', 'user/read'); }); - ✅ 正确写法(数组,需配合配置式路由):
return [ '__domain__' => [ 'm' => 'mobile', ], ];—— 注意这个写法要求url_domain_deploy开启,且必须放在route/app.php的 return 中 - ❌ 错误写法:
Route::domain('m.example.com', 'mobile')(字符串路径)、Route::domain('m.example.com', 'mobile/index')、Route::domain('m.example.com', 'application/mobile')
多域名共用同一模块时,别和 bind() 混用
比如你希望 www.example.com 和 pc.example.com 都走 index 模块,但又在入口文件写了 \think\Route::bind('index'),就会出问题。
-
bind()是全局入口绑定,作用于整个应用生命周期;domain()是路由层匹配,只影响指定域名下的请求解析 - 两者叠加会导致模块前缀重复,例如请求
pc.example.com/可能被解析为index\index\controller\Index,最终报错Class index\controller\index does not exist - 解决办法:删掉入口文件里的
bind(),全部用Route::domain()显式管理;或者只用bind()+url_domain_deploy配合__domain__配置,二者不混用
真正容易被忽略的,是本地开发时 HTTP_HOST 带端口的问题——localhost:8000 和 Route::domain('test.com') 根本不匹配,得写成 Route::domain('localhost:8000') 或加环境判断。这点不处理,调试时永远 404。



















