域名绑定必须写在route.php中才生效,route::domain()第二参数须为闭包或数组,不可为字符串;本地调试需配hosts和虚拟主机,确保http_host匹配。

域名绑定必须写在 route.php,不是配置文件也不是中间件
ThinkPHP5 的域名绑定是路由层行为,只在 route.php(通常是 app/route.php)中用 Route::domain() 定义才生效。写在 config/app.php、app/middleware.php 或控制器里,完全不触发匹配。
常见翻车点:
-
Route::domain('admin.example.com', 'admin')—— 第二个参数不能是字符串,会报Invalid route rule - 把规则塞进
config/route.php—— 这个文件只用于闭包式路由定义,不支持domain()分组 - 误以为要配合
bind('admin')一起用 ——bind是全局模块绑定,和domain冲突,会导致类路径重复(如admin\controller\admin\index)
Route::domain() 后必须接闭包或数组,不能光写域名
ThinkPHP5 不允许孤立的域名声明,Route::domain('m.example.com') 单独一行会静默失效。它必须携带该域名下所有子路由的定义方式:
- 推荐闭包写法:包裹完整路由逻辑,作用域隔离,可复用
Route::get()、Route::resource()等 - 数组写法也行:
Route::domain('api.example.com', require 'route/api.php'),但api.php必须return []路由定义数组 - 不支持直接传模块名字符串,比如
'mobile'或'mobile/index'—— 那是 ThinkPHP3 的旧语法,TP5 已废弃
正确示例:
Route::domain('m.example.com', function () {
Route::get('/', 'mobile/Index/index');
Route::get('list', 'mobile/List/index');
});
本地调试必须配 hosts + Web 服务器虚拟主机,否则 HTTP_HOST 匹配失败
ThinkPHP5 只读取 $_SERVER['HTTP_HOST'] 做匹配。如果你浏览器访问的是 http://127.0.0.1:8000 或 localhost,哪怕路由写了 Route::domain('m.example.com'),也永远不命中。
必须同时满足三件事:
- 修改系统
hosts文件,加一行:127.0.0.1 m.example.com - Web 服务器(Apache/Nginx)配好虚拟主机,
ServerName或server_name设为m.example.com,DocumentRoot指向项目public/目录 - 浏览器真实访问
http://m.example.com(带协议,不能只输域名)
漏掉任意一环,HTTP_HOST 就不是你写的那个域名,框架压根不会进入 domain 分支。
泛域名和多级域名要注意通配符位置和优先级
TP5 支持 Route::domain('*', ...) 和 Route::domain('*.example.com', ...),但有硬性限制:
- 通配符规则必须放在所有精确域名规则之后,否则会提前截断匹配
-
*匹配所有 Host,包括localhost、127.0.0.1,慎用;*.example.com不匹配example.com(根域名),需单独再写一条 - 如果用了
url_domain_root配置(如'url_domain_root' => 'example.com'),它只影响 URL 生成,不影响路由匹配 —— 匹配仍只看HTTP_HOST
典型陷阱:本地开发写 Route::domain('*', ...) 后,连 php think optimize:route 命令都可能因 Host 不合法而报错,建议调试期用明确域名。
DocumentRoot 是否真正指向了项目的 public/ 目录 —— 域名再对,入口文件没加载,整个路由层就启动不了。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











