swoole原生http server不解析host头做路由,也不支持nginx式server_name多级子域名分发;必须在onrequest中用$_server['http_host']手动判断并路由,或v4.6+启用sni仅实现https证书切换。

直接说结论:Swoole 原生 HTTP Server 不解析 Host 头做路由,也不支持 server_name 类 Nginx 式的多级子域名自动分发;必须靠 PHP 层用 $_SERVER['HTTP_HOST'] 手动判断 + 路由分发,或升级到 v4.6+ 利用 SNI 实现 HTTPS 多域名证书切换(仅限 TLS 层,不解决 HTTP 路由)。
为什么 Swoole 默认不识别 api.admin.example.com?
Swoole 的 Http\Server 是底层 TCP/HTTP 协议栈实现,它把所有请求都交给同一个 onRequest 回调,不像 Apache/Nginx 那样在协议层就根据 Host 头匹配虚拟主机。它不会主动拆解 admin.api.example.com 并路由到不同逻辑——这个事得你代码里干。
常见错误现象:
– 所有子域名都返回同一套响应(比如全走 index 应用)
– $_SERVER['SERVER_NAME'] 恒为配置值(如 example.com),不是真实请求头
– 用 $_SERVER['HTTP_HOST'] 却没做 trim 或大小写归一化,导致 API.ADMIN.EXAMPLE.COM 匹配失败
所以关键动作只有两个:
– 确保客户端请求带了正确的 Host 头(浏览器、curl、Postman 都默认带)
– 在 onRequest 里用 $_SERVER['HTTP_HOST'] 做字符串或正则判断
PHP 层怎么手动路由多级子域名?
别指望框架自动识别,老老实实写判断逻辑。以下写法可直接复用:
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
$host = strtolower(trim($_SERVER['HTTP_HOST'] ?? ''));
if (preg_match('/^api\.admin\.example\.com$/', $host)) {
// 加载 admin-api 模块
include __DIR__ . '/app/admin_api/index.php';
} elseif (preg_match('/^admin\.example\.com$/', $host)) {
include __DIR__ . '/app/admin/index.php';
} elseif (preg_match('/^example\.com$/', $host) || preg_match('/^www\.example\.com$/', $host)) {
include __DIR__ . '/app/web/index.php';
} else {
http_response_code(404);
echo 'Unknown host';
}
要点:
– 必须用 $_SERVER['HTTP_HOST'],不是 $_SERVER['SERVER_NAME']
– 用 strtolower 统一小写,避免大小写敏感问题
– 正则结尾加 $,防止 api.admin.example.com.hacker.com 误匹配
– 如果项目已用 ThinkPHP/Slim/Laravel,优先走它们的域名路由机制(如 TP6 的 Route::domain()),别重复造轮子
Swoole v4.6+ 的 SNI 支持能帮上忙吗?
能,但只解决 HTTPS 证书切换,不解决 HTTP 路由。SNI 是 TLS 握手阶段的事,发生在 HTTP 请求之前。它让 Swoole 能根据 Client Hello 里的 hostname 选择对应证书,从而支持 cs.php.net 和 uk.php.net 同时用不同证书跑在 443 端口。
但它不会:
– 修改 $_SERVER['HTTP_HOST'] 的值
– 自动把 api.example.com 的请求转发给某个子服务
– 替代你在 onRequest 里写的域名判断逻辑
要启用 SNI,必须:
– 升级 Swoole ≥ v4.6
– 在 $server->set() 中传入 'ssl_sni_certs' 二维数组,key 是完整域名(如 'api.example.com'),value 是证书路径
– 启动时开启 SSL:new Server('0.0.0.0', 9501, SWOOLE_SOCK_TCP | SWOOLE_SSL)
– 客户端访问必须用 HTTPS,HTTP 请求仍走普通端口(如 9501),且无 SNI 行为
容易被忽略的兼容性细节
– Windows 下 hosts 文件不支持通配符,127.0.0.1 *.example.com 无效,每个测试域名(admin.example.com、api.admin.example.com)都得单独一行
– Swoole 的 onRequest 回调中,$_SERVER 数组是模拟生成的,HTTP_HOST 来自原始请求头,但其他字段(如 REQUEST_URI)可能和 Apache/Nginx 行为略有差异,建议打印 print_r($_SERVER) 确认现场值
– 如果用了协程 MySQL 或 Redis,确保每个子域名逻辑的连接池隔离,别让 api 的 DB 连接被 admin 逻辑意外复用
– 生产环境别用 file_get_contents 或 include 动态加载,应提前注册好应用映射表,用类加载器或 DI 容器管理










