OpenResty可通过lua-resty-websocket模块实现WebSocket功能,核心是作为轻量网关处理握手、维持长连接,并借助Redis PUB/SUB完成跨进程消息中转;需配置协议升级头、合理设置超时与帧长、解析文本消息、主动关闭连接、利用Redis订阅/发布及共享字典缓存状态。

OpenResty 本身不原生支持 WebSocket 协议栈,但通过 lua-resty-websocket 模块 + Lua 脚本,可以高效实现 WebSocket 连接管理与消息实时转发。关键不在“写一个 WebSocket 服务器”,而在于把 OpenResty 当作轻量网关:处理握手、维持长连接、借助外部服务(如 Redis)完成跨连接/跨进程的消息中转。
WebSocket 握手与连接建立
Nginx 层需正确升级 HTTP 协议为 WebSocket,并交由 Lua 处理后续帧通信:
- 在
location块中启用协议升级头:proxy_set_header Upgrade $http_upgrade和Connection "upgrade" - 禁用连接自动关闭:
lua_check_client_abort on,并注册断开回调(如清理 Redis 订阅) - 使用
resty.websocket.server:new()创建 WebSocket 实例,设置合理超时(如timeout = 60000)和最大帧长度
消息接收与解析
连接建立后,用循环持续接收客户端发来的帧:
- 调用
wb:recv_frame()获取data(原始字符串或 table)、typ("text"/"binary"/"close") - 对
typ == "text"的消息,通常用cjson.decode(data)解析为 Lua table,提取to(目标用户)、msg等字段 - 遇到
"close"类型需主动调用wb:send_close()并退出循环,避免资源泄漏
消息转发依赖 Redis PUB/SUB
OpenResty 的每个 worker 是隔离的,无法直接向其他 worker 的连接发消息。Redis 是最常用、低延迟的中转方案:
- 连接 Redis(
resty.redis),用publish将消息推送到频道(如"chat:room1"或"user:123") - 所有监听同一频道的客户端(通过各自 worker 中的
subscribe)会实时收到通知 - 服务端可另起一个 Lua 协程(或用
init_worker_by_lua启动后台订阅器)统一监听频道,再分发给对应连接
连接生命周期与状态维护
真实场景需区分“谁连了”“连在哪台 worker”“是否还活跃”:
- 连接成功时,将用户 ID 与当前 worker 标识(如
ngx.worker.id())存入 Redis Hash(如HSET user_conn:123 worker 2 addr 10.0.1.5) - 发送消息前先查 Redis,确认目标在线且知道该走哪个 worker;若不在当前 worker,则 publish 到对应频道或触发跨 worker 通知
- 结合
ngx.shared.DICT缓存高频查询(如房间成员列表),减少 Redis RTT


















