Hyperf单端口混合协议必须同时开启open_http_protocol和open_websocket_protocol,且server类型必须为SERVER_WEBSOCKET,否则Swoole无法自动识别并分流HTTP与WebSocket请求,导致握手失败或HTTP请求被拒绝。

Hyperf 单协议服务器(比如只开 HTTP 或只开 WebSocket)无法复用端口,导致运维复杂、NAT/防火墙策略冗余、客户端连接管理困难。要真正解决这个问题,必须启用混合协议服务——不是靠反向代理拼凑,而是让 Swoole 在单个 TCP 端口上智能识别并分发请求。
为什么 open_http_protocol 和 open_websocket_protocol 必须同时开启
Hyperf 的混合协议依赖 Swoole 底层的协议自动识别能力。仅配置 ON_HAND_SHAKE 回调但不启用 open_websocket_protocol,会导致 WebSocket 握手失败后直接断连;反之,若没开 open_http_protocol,普通 HTTP 请求会因协议头不匹配被 Swoole 拒绝,返回空响应或 400 错误。
-
open_http_protocol => true:允许 Swoole 解析 HTTP/1.1 请求头,并触发ON_REQUEST -
open_websocket_protocol => true:启用 WebSocket 协议升级检测,Swoole 会检查Upgrade: websocket和Sec-WebSocket-Key头 - 二者缺一不可,且必须在同一个
SERVER_WEBSOCKET类型的 server 配置中生效
type 必须设为 Server::SERVER_WEBSOCKET,不能用 Server::SERVER_HTTP
很多人误以为“HTTP + WS”等于两个 server,于是尝试在 server.php 里并列定义两个 server —— 这样会占用两个端口,完全失去混合意义。Hyperf 的混合能力只在 SERVER_WEBSOCKET 类型下激活,因为只有该类型才注册了完整的协议协商逻辑(包括 HTTP fallback 路径)。
- 即使你不需要 WebSocket 功能,只要想复用端口承载 HTTP 请求,也必须用
SERVER_WEBSOCKET类型 -
SERVER_HTTP类型压根不处理ON_HAND_SHAKE回调,也无法识别 Upgrade 请求 - 启动时若看到
Worker#0 started但无WebSocket Server listening提示,大概率是 type 写错了
握手阶段的 onHandShake 不是可选钩子,而是协议分流关键点
Hyperf 把协议判断逻辑下沉到了 onHandShake 回调里。它不是用来“做鉴权”的附加步骤,而是决定这个连接后续走 HTTP 流程还是 WebSocket 流程的开关。
- Swoole 在收到请求后,先尝试按 WebSocket 握手解析;失败则 fallback 到 HTTP 流程 —— 这个 fallback 行为由
onHandShake的返回值控制 - 如果在
onHandShake里抛出异常或返回false,Swoole 会终止连接,HTTP 请求也会丢失 - 正确做法是在该回调里只做轻量校验(如检查 Origin、Token),然后无条件返回
true,把路由决策交给后续中间件或控制器
最容易被忽略的是:混合服务上线后,curl http://127.0.0.1:9501 能通不代表 WebSocket 就一定可用——必须用真实浏览器或 wscat 发起 Upgrade 请求,才能验证协议识别是否真正生效。任何绕过 ON_HAND_SHAKE 的测试,都只是在测 HTTP 子集。











