ThinkPHP多域名绑定依赖domain_bind.php配置文件而非路由规则,该文件需置于config/目录下并返回域名到模块的映射数组,未正确配置则Route::domain()等路由定义无效。

ThinkPHP 多域名绑定靠 domain_bind.php,不是靠路由规则
多域名绑定在 ThinkPHP 中本质是「入口映射」,不是「路由匹配」。你写一堆 Route::domain() 或在 route.php 里配子域名,根本不会生效——除非你先启用域名绑定机制。
真正起作用的是应用根目录下的 config/domain_bind.php(5.1/6.x)或 app/domain.php(早期 5.0)。这个文件必须存在且返回数组,格式为 ['域名' => '模块名/控制器名']。
- 5.1+ 版本:该文件需放在
config/目录下,键名必须是完整域名(如'admin.example.com'),不能带协议或路径 - 值可以是字符串(如
'admin/index')或数组(如['module' => 'admin', 'controller' => 'index']) - 如果绑定后访问仍进默认首页,大概率是
domain_bind.php没被加载——检查是否拼错文件名、是否在正确 config 目录、是否被其他配置覆盖
子域名路由 Route::domain() 只在绑定后才生效
Route::domain() 本身不触发域名绑定,它只是给已绑定的域名“加一层路由解析”。比如你绑定了 'api.example.com' => 'api',那后续所有对 api.example.com 的请求才会进入 api 模块,此时 Route::domain('api.example.com', ...) 配置才开始接管 URL 路径解析。
- 没在
domain_bind.php中声明的域名,调用Route::domain()完全无效 - 同一个域名多次调用
Route::domain()会合并规则,但优先级低于全局路由;建议只在一个地方集中定义 - 注意闭包定义方式:
Route::domain('m.example.com', function () { Route::get('user', 'mobile/user/index'); });,别漏掉闭包里的Route::前缀
HTTPS 域名和带 www 的变体要单独绑定
ThinkPHP 的域名绑定是严格字符串匹配,'example.com' 和 'www.example.com' 视为两个完全不同的域名,必须分别配置。HTTPS 同理——协议不影响绑定逻辑,但如果你用 Nginx/Apache 把 HTTPS 请求重写成 HTTP 再转发给 PHP,那 PHP 看到的仍是 http 协议下的 Host,绑定依然按 Host 字符串来。
立即学习“PHP免费学习笔记(深入)”;
- 常见坑:本地开发用
localhost:8000测试,却在domain_bind.php写了'test.local',结果永远不命中 - 调试时可用
var_dump($_SERVER['HTTP_HOST'])确认实际收到的 Host 值,再对照配置项 - 生产环境若需泛域名支持(如
*.example.com),TP 原生不支持,得靠 Web 服务器做反向代理 + 统一 Host 转发,再在 PHP 层用中间件动态判断
多入口与多域名容易混淆,但它们解决的是不同问题
多入口(如 admin.php、api.php)是物理文件隔离,每个入口有自己的 App::run();多域名绑定是逻辑路由分流,共用同一个入口文件(通常是 index.php)。两者可并存,但别指望删掉 admin.php 还能靠域名绑定自动切到 admin 模块——除非你把所有流量都导向 index.php 并完成绑定配置。
- Apache 下确保
.htaccess把所有请求都 rewrite 到index.php,否则子域名请求可能 404 - Nginx 用户注意
server_name必须包含所有要绑定的域名,且root指向项目根目录,不是 public - 如果用了多入口又配了域名绑定,记得检查每个入口是否都加载了 domain_bind 配置——默认只有
index.php会自动加载config/下的文件
domain_bind.php 文件位置不对、Host 值和配置不一致、或者压根忘了这个文件才是开关。



















