Laravel 12 中需用 Route::domain() 在 RouteServiceProvider::mapWebRoutes() 中注册子域名路由组,配合 Nginx 泛解析(server_name *.example.com)、独立路由文件及可选中间件提取子域名参数,不可在 web.php 中直接定义。

在 Laravel 12 中,给不同子域名指向不同控制器和方法,核心是用 Route::domain() 分组路由,并确保它在正确位置注册、配合 Web 服务器配置和可选的中间件逻辑。这不是靠改路径或加前缀,而是基于 HTTP 请求头中的 Host 值做精准匹配。
必须在 RouteServiceProvider 中注册子域名路由
不能把 Route::domain() 写在 routes/web.php 里——它必须放在 app/Providers/RouteServiceProvider.php 的 mapWebRoutes() 方法中。否则 {tenant} 或 {sub} 占位符无法被解析,控制器和中间件也拿不到子域名值。
示例(修改 app/Providers/RouteServiceProvider.php):
// app/Providers/RouteServiceProvider.php
use Illuminate\Support\Facades\Route;
protected function mapWebRoutes(): void
{
Route::domain('shop.example.com')->group(function () {
require base_path('routes/shop.php');
});
Route::domain('admin.example.com')->group(function () {
require base_path('routes/admin.php');
});
Route::domain('{sub}.example.com')->group(function () {
require base_path('routes/tenant.php');
});
}
```
为每个子域名定义独立路由文件
拆分路由到不同文件,便于维护和隔离逻辑。每个文件只处理对应子域名下的请求。
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
-
routes/shop.php:只写 shop.example.com 的路由,例如:
```php
use App\Http\Controllers\ShopController;
Route::get('/', [ShopController::class, 'index']);
Route::get('/products', [ShopController::class, 'list']);
``` -
routes/admin.php:只写 admin.example.com 的路由,例如:
```php
use App\Http\Controllers\Admin\DashboardController;
Route::get('/', [DashboardController::class, 'home']);
Route::resource('users', Admin\UserController::class);
``` -
routes/tenant.php:处理通配子域名(如 client1.example.com),可结合中间件识别租户:
```php
Route::middleware('initialize.tenant')->group(function () {
Route::get('/', function (Request $request) {
$tenant = $request->route('sub');
return view('tenant.welcome', compact('tenant'));
});
});
```
DNS 和 Web 服务器必须先支持泛解析
如果 Nginx 或 Apache 没把请求真正转发过来,Laravel 根本收不到 Host 头,Route::domain() 就完全无效。
- Nginx 配置示例(关键点是
server_name *.example.com;):
```nginx
server {
listen 80;
server_name *.example.com;
root /var/www/example.com/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
}
``` - 本地开发时,需在
/etc/hosts添加多行:127.0.0.1 shop.example.com127.0.0.1 admin.example.com127.0.0.1 client1.example.com - DNS 必须已设置泛解析(
*.example.com → A 记录指向你的服务器 IP)
可选:用中间件统一提取并传递子域名信息
若多个子域名需要共享部分逻辑(比如记录日志前缀、切换数据库、加载租户配置),建议建一个中间件,在请求生命周期早期拿到子域名值。
- 创建中间件:
```bash
php artisan make:middleware ResolveSubdomain
``` - 在
handle()中获取:
```php
$sub = $request->route('sub') ?? $request->route('tenant') ?? null;
if ($sub) {
$request->attributes->set('subdomain', $sub);
// 可继续查库、设 config、切 DB 连接等
}
``` - 在路由组中应用:
```php
Route::domain('{sub}.example.com')->middleware('resolve.subdomain')->group(...);
```










