thinkphp通过泛解析+动态子域名识别实现商户id自动映射,核心步骤为:nginx/apache配置通配符域名指向统一入口;中间件中解析host获取子域名并查库验证;将merchant_id注入request供全局使用;路由、查询、模板、文件路径等均自动适配商户上下文。

ThinkPHP 实现二级域名自动识别商户 ID,核心在于解析请求的子域名、映射到对应商户,并在应用层统一处理。不需要为每个商户单独配置域名或路由,靠动态解析 + 数据库查询即可完成。
一、Nginx/Apache 通配符域名配置
确保服务器已支持泛解析,将所有 *.yourdomain.com 请求指向同一入口(如 public/index.php):
- Nginx 示例:在 server 块中添加 server_name ~^(?
.+)\.yourdomain\.com$; ,并在 location 中正常转发 PHP 请求 - Apache 需开启 mod_vhost_alias,使用 VirtualDocumentRoot 或通过 .htaccess 捕获 HTTP_HOST
- 本地开发可修改 hosts 文件模拟,例如:127.0.0.1 shop1.yourdomain.com、127.0.0.1 shop2.yourdomain.com
二、ThinkPHP 中提取并验证子域名
在全局中间件(如 app/middleware/DomainParse.php)或 Base Controller 构造方法中执行:
- 用 request()->host() 获取完整域名,用 explode('.', $host, 3) 分割取第一段作为 subdomain
- 过滤非法字符(仅允许字母、数字、下划线),排除 www/admin/api 等保留名
- 查数据库 merchant 表(字段如 subdomain、id、status),确认该子域名是否启用且存在
- 查到后将 $merchantId 写入 Request 对象: request()->withAttr('merchant_id', $id)
三、路由与业务逻辑自动适配商户上下文
后续所有控制器、模型、服务层均可直接获取当前商户 ID,无需重复判断:
- 控制器中用 request()->attr('merchant_id') 或封装成 $this->mid 属性
- 数据库查询默认加条件: where('merchant_id', $this->mid),避免数据越界
- 模板中可动态输出商户信息,如 {$Think.request.merchant_id} 或通过 View::assign 注入
- 文件上传路径、缓存键名、日志前缀等都带上 mid,实现物理隔离
四、注意事项与扩展建议
避免踩坑,提升稳定性和安全性:
- 主站域名(如 yourdomain.com)需单独处理,不参与商户匹配,可跳转到登录页或默认首页
- 子域名变更时,清空相关缓存(如 Redis 中的 subdomain → id 映射),推荐加缓存失效钩子
- 若需 HTTPS,SSL 证书必须支持泛域名(*.yourdomain.com),单域名证书无效
- 后续支持多语言或多区域,可在子域名基础上叠加路径(如 shop1.yourdomain.com/zh-CN/),仍由同一套逻辑接管
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











