ThinkPHP中应优先使用request()->host()获取域名,它自动处理反向代理环境;subDomain()需开启url_domain_deploy配置才生效;域名判断须归一化并确保代理透传Host头。

如何在ThinkPHP中获取当前请求的域名
直接用 request()->domain() 就能拿到完整协议+域名(如 https://example.com),但多数业务只需要主域名或子域名部分。别用 $_SERVER['HTTP_HOST'] 手动拼,它可能被伪造,且不兼容 CLI 或某些反向代理环境。
常见错误是直接解析 HTTP_HOST 后做字符串匹配,结果在 Nginx + FastCGI 或容器部署时拿到的是内网地址或端口(如 172.18.0.3:8080)——request()->host() 会自动处理这些场景,更可靠。
-
request()->domain():返回带协议的完整域名(https://xxx.com),适合生成绝对 URL -
request()->host():返回 Host 头原始值(xxx.com或sub.xxx.com),最常用 -
request()->subDomain():自动提取子域名(admin来自admin.xxx.com),依赖配置中的url_domain_deploy
为什么 request()->subDomain() 有时返回空
不是代码写错了,而是 ThinkPHP 默认不开启子域名解析。必须在 config/app.php 中显式打开:'url_domain_deploy' => true,否则 subDomain() 始终为空。
开启后还会触发额外行为:路由会自动把子域名作为模块名尝试匹配(比如访问 api.xxx.com,会优先找 app/api/ 下的控制器)。如果没这个需求,反而会造成 404,这时候得关掉,改用 request()->host() 自己切分。
立即学习“PHP免费学习笔记(深入)”;
- 子域名解析依赖
url_domain_deploy配置项,不设为true就无效 - 开启后,
route/目录下需有对应子域名命名的子目录,否则路由失败 - 本地开发用
localhost测试时,sub.localhost不会被识别——浏览器不支持多级 localhost 子域,得绑 hosts 改成真实域名
判断用户来源域名的典型业务场景
比如 SaaS 系统要根据域名加载不同租户配置,或者多站点共用一套后台但前端展示不同 logo 和导航。这时候不能只比对完整域名,得考虑 www 跳转、HTTPS 升级、测试环境等变量。
推荐做法是统一归一化后再判断:去掉协议、统一小写、剥离 www 前缀。别用 strpos() 硬匹配,容易漏掉大小写或协议差异。
- 用
str_replace('www.', '', strtolower(parse_url(request()->domain(), PHP_URL_HOST)))提取纯净主域 - 配置里存归一化后的域名白名单(如
['xxx.com', 'yyy.net']),避免硬编码 - 注意 CDN 或 WAF 可能修改
Host头,若后端实际监听的是内网 IP,需在入口层(Nginx)加proxy_set_header Host $host;
线上环境常见域名误判问题
最常踩的坑是开发时一切正常,上线后 request()->host() 返回的是负载均衡 IP 或容器内部域名(如 nginx-7d8b9c4f56-xyz)。这不是 ThinkPHP 的 bug,而是 HTTP 请求头根本没传过来。
根本原因是反向代理没透传 Host 头。Nginx 必须显式配置:proxy_set_header Host $host; 和 proxy_set_header X-Real-IP $remote_addr;。Apache 或 Caddy 同理,缺一不可。
- 检查
request()->header('host')是否和预期一致,这是第一排查点 - ThinkPHP 的
request()对象默认信任X-Forwarded-Host,但很多云厂商(如阿里云 SLB)并不设置它,只设X-Forwarded-For - 若无法修改代理层,可临时在入口
public/index.php加一行:$_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST'] ?? $_SERVER['HTTP_HOST'];,但属于权宜之计



















