route::domain() 是以子域名作为路由分组触发条件的机制,仅在 route/app.php 中生效,须接闭包或数组,不支持通配符,需显式声明完整域名并配合 pattern 限制变量,多域名共享路由应传数组而非重复定义,且不可嵌套。

Route::domain() 不是“给子域名加路由”,而是“用子域名作为路由分组的触发条件”——它只在 route/app.php 里生效,且必须接闭包或数组,否则直接报错。
Route::domain() 必须写在 route/app.php 中
写在 config/route.php、app/middleware.php 或控制器里都无效。框架只在 route/app.php 的加载阶段扫描 Route::domain() 调用;其他位置的调用会被忽略,请求进来时根本不会匹配。
- 多应用模式下(如 app/admin/),仍统一写在根 route/app.php,不能拆到各应用自己的 route/ 目录下
- 若用了
route_domain配置(非 domain_bind),它只是 url() 生成时补域名用的,和 Route::domain() 的匹配逻辑完全无关 - 本地调试时,
HTTP_HOST值含端口(如localhost:8000),必须写成Route::domain('localhost:8000', ...)才能命中
子域名必须显式声明为变量,不能用 * 通配符
TP6 不支持 Route::domain('*') 或 Route::domain('{sub}') 这类裸变量写法,会抛出 InvalidArgumentException: Domain route not support wildcard。
- 正确写法是完整域名带变量:例如
Route::domain('{sub}.example.com', function ($sub) { ... }) - 必须配合
->pattern(['sub' => '\w+'])限制匹配,否则可能匹配空值或路径穿越字符 -
$sub会自动注入闭包参数,也可在控制器方法签名中接收:public function index($sub) { ... } -
request()->subDomain()在 Route::domain() 启用后失效,不要依赖它
多个子域名共用同一套路由?用数组传参
想让 admin.example.com 和 api.example.com 共享相同路由结构,别写两个 Route::domain(),容易因注册顺序导致后一个被前一个吞掉。
- 直接传域名数组:
Route::domain(['admin.example.com', 'api.example.com'], function () { ... }) - 数组内域名必须完全一致(大小写敏感),不支持通配或正则
- 闭包内定义的路由,对每个域名都独立生效,但代码只需写一遍
- 如果需要差异化中间件(比如 admin 要登录校验、api 要 token 校验),得在闭包内手动加
->middleware(),不能靠全局中间件自动区分
闭包里不能再嵌套 Route::domain()
Route::domain() 的闭包作用域是“该域名下的全部路由入口”,它本身不构成嵌套层级。以下写法非法:
Route::domain('admin.example.com', function () {
Route::domain('backup.admin.example.com', function () { // ❌ 报错:Cannot nest domain routes
Route::get('log', 'Log/index');
});
});
- 真要处理 backup.admin.example.com,得单独再写一层顶层
Route::domain('backup.admin.example.com', ...) - 所有
Route::domain()必须平级注册在 route/app.php 中,不能包裹、不能条件判断 - 泛域名(如
*.example.com)需用domain_bind配置 + 多应用,而非 Route::domain()
最易被忽略的是:Route::domain() 只切换路由解析空间,不切换应用上下文——它不会自动加载对应模块的中间件、配置或数据库连接。要做真正的多站点隔离,得配 domain_bind;只用 Route::domain(),本质还是在同一个应用里做路由分流。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











