直接在route/app.php中用Route::domain()绑定域名到控制器即可生效,无需修改Nginx/Apache配置或添加中间件;第二个参数必须是闭包或数组,不可为字符串路径;本地开发需匹配含端口的HTTP_HOST;多域名共用控制器需显式定义根路径路由;url()函数默认不自动切换域名,需手动指定。

直接在 route/app.php 里用 Route::domain() 绑定域名到控制器即可生效,不需要改 Nginx/Apache 配置,也不需要额外中间件或环境判断。
Route::domain() 第二个参数必须是闭包或数组,不能是字符串路径
常见错误是写成 Route::domain('admin.example.com', 'admin/index/index') —— 这会报 Invalid route rule。ThinkPHP5 不支持字符串形式的控制器绑定,只接受闭包或路由规则数组。
- 正确写法是把该域名下所有路由包裹进闭包:
Route::domain('admin.example.com', function () { Route::get('/', 'admin/index/index'); Route::get('user/:id', 'admin/user/read'); }); - 也可以用数组方式定义(适合规则简单、复用性强的场景):
Route::domain('m.example.com', require 'route/mobile_rules.php');,但mobile_rules.php必须返回一个路由规则数组 - 闭包内可继续使用
Route::resource()、Route::group()等全部路由方法,作用域自动限定在此域名下
本地开发时 HTTP_HOST 含端口,必须显式匹配
比如你用 php -S localhost:8000 启动,$_SERVER['HTTP_HOST'] 实际是 localhost:8000,而你写了 Route::domain('test.com', [...]),那就永远不匹配。
- 调试阶段建议加条件判断:
if (env('APP_DEBUG')) { Route::domain('localhost:8000', [...]); } - 或者统一用 hosts + 真实子域名(如
dev.example.com),并在 hosts 文件里映射到127.0.0.1 - 别依赖浏览器地址栏写的域名,以
$_SERVER['HTTP_HOST']实际值为准,可用dump($_SERVER['HTTP_HOST'])快速验证
多个域名共用同一控制器,但路径不同,得手动定义根路径
比如 admin.example.com/ 想直接访问 admin/index/index,而不是默认跳转到 index/index,就必须显式声明 get('/', ...) 路由。
立即学习“PHP免费学习笔记(深入)”;
-
Route::domain('admin.example.com', function () { Route::get('/', 'admin/index/index'); });才能让首页生效 - 如果不写这行,访问
admin.example.com/会 fallback 到全局默认路由(通常是index/index),和域名绑定无关 - 同理,
admin.example.com/user要生效,也得明确写Route::get('user', 'admin/user/index'),不能指望框架自动推导
最易忽略的是:域名绑定后,url() 函数默认仍生成当前请求域名下的 URL,不会自动带上目标域名。如果要在 www.example.com 页面里生成 admin.example.com 的链接,必须手动传参:url('admin/index/index', [], true, 'https://admin.example.com') 或配置 ['domain' => 'admin.example.com']。否则前端跳转会出错。



















