必须用 Route::domain('example.com') 显式包裹主域名路由,否则无约束路由会匹配所有域名;路由顺序需按通配子域、特定子域、主域名分组排列,且 Web 服务器须正确透传 Host 头。

在 Laravel 11 中,若想让一组中央路由(如首页、联系页等)**仅响应主域名**(例如 example.com),而**不被子域名或其它绑定域名匹配**,不能依赖默认的无约束路由,必须显式用 Route::domain() 包裹,并确保它不被更宽泛的路由“兜底”捕获。
必须把主域名路由写在 Route::domain() 里
Laravel 路由不自动区分域名。只要没加 domain() 约束,Route::get('/') 这类路由会匹配任意 Host 头——包括 admin.example.com、api.example.com 甚至测试用的 test.local。所以,主域名逻辑不能放在全局 group 或裸写路由中。
- ✅ 正确:用
Route::domain('example.com')明确包裹主站所有路由 - ❌ 错误:把
Route::get('/', ...)写在Route::domain()外,还指望它只对主域名生效
路由顺序决定谁先匹配,主域名组要靠前但不最早
虽然 Route::domain() 必须显式声明,但它的注册顺序影响实际匹配结果。原则是:
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
- 通配子域名(如
{sub}.example.com)应最优先,避免被主域名路由拦截 - 具体子域名(如
admin.example.com)其次 - 主域名(
example.com)路由组紧随其后 - 绝对不要把无 domain 约束的
Route::get()放在这些之前,否则它会成为“万能兜底”
示例结构(routes/web.php):
// 1. 通配子域名(最高优先级)
Route::domain('{sub}.example.com')->group(function () {
Route::get('/health', function (Request $request) {
return response()->json(['sub' => $request->route('sub')]);
});
});
// 2. 特定子域名
Route::domain('admin.example.com')->group(function () {
Route::get('/', [AdminController::class, 'dashboard']);
});
// 3. 主域名 —— 仅此处的路由响应 example.com
Route::domain('example.com')->group(function () {
Route::get('/', [HomeController::class, 'index']);
Route::get('/about', [PageController::class, 'about']);
Route::get('/contact', [PageController::class, 'contact']);
});
// 4. ❌ 不要在这里加任何无 domain 的 Route::get()!
注意 Host 头透传和本地开发配置
即使代码写对,如果 Web 服务器未正确传递 Host 请求头,Route::domain() 就无法工作。
- Apache:确认
VirtualHost中有ServerName example.com和对应ServerAlias,且UseCanonicalName Off - Nginx:检查
server_name是否覆盖全部目标域名,并确保fastcgi_param HTTP_HOST $http_host;存在 - 本地开发:修改
/etc/hosts添加多行,如:127.0.0.1 example.com127.0.0.1 admin.example.com127.0.0.1 shop.example.com
补充:避免中间件里做域名判断
有人试图在中间件中读取 $request->getHost() 然后重定向或跳转,这属于运行时干预,绕过了 Laravel 路由缓存机制,性能差,也容易导致 HTTPS/HTTP 混合问题。Laravel 原生的 domain() 是编译期匹配,高效且可靠,应作为唯一标准方案。


















