PHP原生不支持WebSocket服务端,需用Swoole(推荐)、Ratchet或Workerman等常驻CLI进程实现;Nginx反代须配置Upgrade和Connection头;前后端需统一JSON格式与编码;消息须落库并建索引保障可追溯性。

PHP本身不支持原生WebSocket服务端,必须借助常驻进程的第三方库或扩展来实现。直接在Apache/Nginx+PHP-FPM环境下运行WebSocket服务会失败——连接卡在pending或立刻断开,这是协议机制决定的,不是代码写错了。
选对服务端运行方式
不能用HTTP服务器托管WebSocket,必须启动独立CLI进程:
- 推荐Swoole(v4.8+):内置
swoole_websocket_server,自动处理握手、帧解析、心跳、ping/pong,生产环境最稳 - 次选Ratchet:基于ReactPHP,依赖
ext-sockets,适合轻量级项目,需手动管理连接容器 - Workerman也可用,但广播逻辑易出错(比如误遍历
$worker->connections导致Call to a member function send() on null)
确保握手能成功响应
浏览器报“Connection closed before receiving a handshake response”,90%是服务端没正确返回101状态码:
- Swoole默认支持,但监听地址必须是
0.0.0.0:9501,不能只绑127.0.0.1 - 若用Nginx反代,必须加两行配置:
proxy_set_header Upgrade $http_upgrade和proxy_set_header Connection "upgrade" - HTTPS站点必须用
wss://协议连接,后端仍可走ws,由Nginx做TLS终止
前后端消息格式要一致
空消息、乱码、静默失败,多数源于数据类型和编码不匹配:
立即学习“PHP免费学习笔记(深入)”;
- 前端发送前必须
JSON.stringify(),不能ws.send({msg:'hello'})直传对象 - 服务端接收后先判断
is_string($data) && !empty($data),再json_decode($data, true) - 中文输出要用
JSON_UNESCAPED_UNICODE:json_encode($msg, JSON_UNESCAPED_UNICODE) -
$connection->send()只接受string,传数组或对象会无声失败
消息要落库且可追溯
在线客服等业务场景,消息不能只存在内存里:
- 建
message表:含session_id、sender_type(user/agent)、sender_id、content、created_at - 建
session表:记录会话生命周期,字段包括id、user_id、agent_id、status(open/closed) - 给
message(session_id, created_at)加复合索引,查历史消息才快 - 服务端收到消息后,先入库再推送,保证离线用户上线后能拉取



















