laravel的route::domain()仅支持字符串模板(如{sub}.example.com),不支持正则,{sub}默认只匹配一级子域;需多级时应手动解析$sub或改用路径前缀;域名路由须在map()中定义,且app_url配置不当会导致url生成错误。

如何用 Route::domain() 匹配多级子域名
直接支持,但必须提前声明完整域名模式,不能靠正则模糊匹配。Laravel 的 Route::domain() 只接受字符串模板(含通配符 {sub}),不支持原生正则,所以 *.example.com 这种写法无效。
常见错误是把 Route::domain('{sub}.example.com') 当成通配所有子域——它确实能捕获 api.example.com 或 admin.example.com,但不会匹配 v1.api.example.com 这类三级域名,因为 {sub} 默认只占一级。
- 若需支持任意深度子域(如
v1.api.example.com),改用Route::domain('{sub}.example.com')+ 在控制器里手动解析$sub字符串,例如explode('.', $sub) - 更稳妥的做法是把多级子域“扁平化”:统一用二级域名承载业务(
api-v1.example.com),或改用路径前缀(example.com/v1/api/...) -
Route::domain()必须在 RouteServiceProvider 的map()方法中调用,不能放在闭包路由文件里;否则会因域名绑定时机过晚而失效
为什么 Request::getHost() 和 url()->to() 生成的链接可能出错
因为 Laravel 默认根据当前请求的 Host 头构建 URL,但多级域名下常出现「路由匹配了,链接却指向错误域名」的问题——比如访问 admin.example.com 时,url()->to('dashboard') 却生成 http://example.com/dashboard。
根本原因是 APP_URL 配置项被硬编码为单域名,而 Laravel 的 URL 生成器优先信任它,而非实际请求头。
- 临时修复:在
AppServiceProvider::boot()中动态设置URL::forceRootUrl(request()->getSchemeAndHttpHost()) - 长期方案:把
APP_URL改成空值,并确保服务器(Nginx/Apache)正确透传Host头;否则request()->getHost()可能返回 IP 或默认域名 - 注意缓存影响:如果开了路由缓存(
php artisan route:cache),Route::domain()相关路由会被固化,此时修改APP_URL或中间件逻辑不会实时生效
使用 Route::group(['domain' => ...]) 时的嵌套陷阱
看似方便,但容易忽略作用域污染:外层 domain 分组会覆盖内层定义,且无法叠加。例如 Route::domain('{sub}.example.com')->group(...) 内再写 ->domain('{v}.api.example.com') 是无效的,第二个 domain() 调用会被忽略。
更隐蔽的问题是中间件执行顺序——域名路由分组的中间件会在请求进入控制器前运行,但如果中间件里依赖了未初始化的容器服务(比如自定义域名解析器),会抛出 BindingResolutionException。
- 避免嵌套
domain分组,改用单一顶层Route::domain('{wildcard}.example.com'),然后在中间件里做细分判断 - 若需按子域加载不同配置(如数据库连接),不要在路由分组里直接调用
Config::set(),应通过服务提供者或请求生命周期早期的事件(如booting)完成 - 测试时记得用真实 Host 头:
php artisan test --filter=TestDomainRouting不足以覆盖,要用Http::withHeaders(['Host' => 'api.example.com'])->get('/')模拟
本地开发时 Nginx / Valet / Sail 的域名配置差异
本地跑不通多级域名,大概率不是代码问题,而是环境没对齐。Valet 默认只响应 *.test,不支持 *.local.test;Sail 的 docker-compose.yml 若没配 extra_hosts,容器内 DNS 解析会失败;Nginx 则常因 server_name 没加通配符导致 404。
- Valet:运行
valet domain test后,再执行valet link admin,访问admin.test即可;但v1.admin.test需手动编辑/etc/resolver/test并重启 mDNSResponder - Sail:在
docker-compose.yml的laravel.test服务下添加extra_hosts: ["v1.api.example.com:host-gateway"],并确保.env中APP_URL设为空 - Nginx:
server_name必须写成server_name ~^(?<subdomain>.+)\.example\.com$;</subdomain>才能捕获变量,单纯写*.example.com是无效语法
真正麻烦的从来不是怎么写路由,而是每次换环境都要重新核对 Host 头、DNS 解析、HTTPS 证书和容器网络这四层是否同时对齐——漏一个,就卡在 502 或混合内容警告里。










