ThinkPHP域名绑定必须写在route/app.php中,其他位置无效;Route::domain()第二参数须为闭包或数组,不可为字符串;本地开发需匹配完整HTTP_HOST(含端口),泛域名路由需置于精确路由之后且不匹配根域名。

域名绑定必须在 route.php 里写,别放错地方
ThinkPHP5 的域名绑定逻辑只在路由加载阶段生效,Route::domain() 必须写在 route/app.php(或你实际使用的主路由文件)中,其他位置——比如 config/route.php、控制器、中间件、甚至 public/index.php —— 都不会被识别。框架启动时只扫描这个文件里的 Route::domain() 调用,其余一概忽略。
常见错误是把绑定逻辑塞进 app/config.php 或试图用 App::bind() 模拟,结果线上请求全部 fallback 到默认模块,404 且无报错。
- 确认你的入口路由文件路径是
route/app.php,不是route/route.php(后者仅用于闭包式路由,不支持域名分组) - 不要在
app/middleware.php里动态调用Route::domain(),它此时已过期 - TP5 不支持多应用模式下的自动域名→应用映射,
config/app.php中的domain_bind配置完全无效
Route::domain() 第二个参数不能是字符串
这是线上最常导致白屏或 500 的坑:Route::domain('admin.example.com', 'admin') 是非法写法,会直接抛出 Invalid route rule 异常。TP5 要求第二个参数必须是闭包函数或路由定义数组,不能是模块名字符串。
正确做法是把该域名下所有路由包裹进一个闭包,例如:
立即学习“PHP免费学习笔记(深入)”;
Route::domain('admin.example.com', function () {
Route::get('/', 'admin.Index/index');
Route::get('user/:id', 'admin.User/read');
Route::post('login', 'admin.Login/check');
});
- 闭包内可自由使用
Route::get()、Route::resource()等,作用域自动限定在此域名下 - 如果路由较多,可抽成独立文件(如
route/admin.php),然后用Route::domain('admin.example.com', require 'route/admin.php'); - 数组方式也行,但返回值必须是标准路由定义数组,不能含任何执行逻辑
线上服务器要配好 DNS 和 Host 头,别指望 Nginx 重写
ThinkPHP5 的域名匹配只读取 $_SERVER['HTTP_HOST'],和 Nginx/Apache 是否做了 rewrite、是否启用了 HTTPS、端口是多少都无关——只要 HTTP_HOST 值能精确匹配你写的 Route::domain() 参数,就能命中。
所以线上部署前必须确保:
- DNS 已将
admin.example.com解析到服务器 IP(A 记录),泛域名用*.example.com(需 DNS 支持) - Nginx 配置中,所有相关域名都指向同一个
public/目录,且不修改Host头(即不用proxy_set_header Host覆盖) - 别在 Nginx 里做
rewrite ^/admin/(.*)$ /$1 break;这类操作——TP5 不需要,反而可能破坏HTTP_HOST - 检查 PHP 日志,确认
$_SERVER['HTTP_HOST']输出的是你期望的纯域名(如admin.example.com),而不是带端口或 IP
泛域名和优先级顺序必须手动控制
TP5 对多个 Route::domain() 规则有硬编码的匹配优先级:完整域名/IP > 二级域名 > 泛三级域名(*.user) > 泛二级域名(*)。它不会按代码顺序匹配,而是按规则类型“从具体到模糊”选。
这意味着如果你同时写了:
<pre class="brush:php;toolbar:false;">Route::domain('*', 'home'); // 泛二级
Route::domain('api.example.com', function () { ... }); // 完整域名
Route::domain('*.example.com', 'api'); // 泛三级(注意:这不是 TP5 原生支持的写法,会失败)
那么 api.example.com 一定走第二条,<code>xxx.example.com 会 fallback 到第一条(因为 *.example.com 在 TP5 中不被识别为合法泛三级规则)。
- TP5 原生只支持
*(泛二级)、blog(二级)、admin.blog(三级)、doc.thinkphp.cn(完整域名)这四类,不支持*.example.com这种写法 - 泛二级
*是兜底项,放在最后定义;更具体的规则(如admin.example.com)必须写在前面 - 本地调试时,
HTTP_HOST可能是localhost:8080,线上却变成admin.example.com,务必区分环境配置
HTTP_HOST 的实际值和路由文件加载时机这两个底层细节。很多问题表面是“域名没绑上”,根子其实是 Nginx 把 Host 头改了,或者路由文件根本没被框架读到。



















