子域名路由既适用于多租户也适用于多项目分发,本质是按Host头分流,不绑定数据库;关键区别在于后续处理逻辑是否需动态切换配置或仅做路由分组与中间件组合。

子域名路由适合多租户还是多项目分发
子域名路由本质是按 Host 头做请求分流,它不绑定数据库或模型,只负责把 admin.example.com 和 shop.example.com 的请求分别导向不同逻辑——所以它既可用于多租户(每个租户一个子域名),也可用于单应用内多业务模块隔离(如后台、API、文档站点共用一套代码)。
关键区别在于后续处理:多租户需在中间件或控制器里根据 $sub 动态切换数据库连接或配置;而多项目分发往往只是路由分组+不同中间件组合,比如:
-
api.example.com→ 绑定api中间件组,走routes/api.php风格逻辑 -
docs.example.com→ 不需要认证,直接返回静态 Markdown 渲染页 -
admin.example.com→ 强制auth+can:manage-system
别硬套“必须多租户才用子域名”,很多 SaaS 后台把管理后台拆成 admin.、客户门户用 app.、开放 API 用 api.,全靠 Route::domain() 分开写,没碰数据库隔离。
Route::domain() 必须放在 routes/web.php 最顶部
Laravel 路由匹配是顺序优先(First Match Wins),Route::domain() 如果写在根域名路由后面,比如:
Route::get('/', function () { return 'home'; });
Route::domain('admin.example.com')->group(...); // ❌ 永远不会执行
浏览器访问 admin.example.com/ 时,/ 这条路由先命中,直接返回 home,子域名分组被跳过。
正确姿势是所有 Route::domain() 必须置于 routes/web.php 文件最上方,早于任何 Route::get()、Route::group() 等根域名定义。通配符 {sub}.example.com 建议放最后,避免把 api.example.com 错匹配成 sub=api 再进通用逻辑。
动态子域名参数 $sub 怎么安全取值
{sub} 是路由参数,不是全局变量,不能靠 request()->route('sub') 取——中间件里 request()->route() 可能为 null,不稳定。
当代理已经知道网站路由或内容URL,并且在启动前需要有效的sitemap XML、sitemap索引或robots.txt引用时,请使用sitemap。这是一个发布构件技能,而不是爬虫或SEO平台。
必须显式声明在闭包参数或控制器方法签名里:
- 闭包写法:
Route::domain('{sub}.example.com')->group(function () { Route::get('/', function ($sub) { return "Hello {$sub}"; }); }); - 控制器写法:路由绑定
Route::get('/', [SubController::class, 'index']),然后public function index($sub) { ... }
强烈建议加约束,比如 ->where('sub', '^[a-z0-9]+(?:-[a-z0-9]+)*$'),防注入和非法字符;若只允许几个固定子域,直接 ->where('sub', 'admin|shop|api') 更安全。
APP_URL 和生成 URL 必须动态化
硬编码 APP_URL=https://example.com 会导致 route()、url()、邮件模板里的链接全部指向根域名,用户点击后丢失子域名上下文。
解决办法是在 config/app.php 中改写 'url' 配置项:
'url' => env('APP_URL', request()->getSchemeAndHttpHost()),
这样 route('user.profile') 生成的链接就是 https://admin.example.com/user/profile,而不是死板的 https://example.com/user/profile。注意:这个写法依赖 request() 全局辅助函数,在命令行或队列任务中不可用,这类场景需手动传参或判断运行环境。
session.domain 也要设为 .example.com(开头带点),否则子域名间无法共享 session;本地开发时 /etc/hosts 必须加对应映射,否则浏览器根本发不出带 Host: admin.example.com 的请求。


















