RxJs webSocket无法连接socket.io实现的WebSocket服务器问题求助
嘿,这个坑我之前踩过!核心原因其实很简单:Socket.IO 并不是标准的 WebSocket 协议实现,它有自己一套自定义的握手机制、帧格式和附加功能,而 RxJS 的 webSocket/WebSocketSubject 是基于原生标准 WebSocket 协议开发的,两者根本不兼容,这就是你遇到问题的根源。
先拆解下你遇到的两个现象:
- 用
http://localhost:8081没反应:RxJS 的 WebSocketSubject 只识别ws:///wss://协议前缀,http://会被直接忽略,自然不会发起连接请求。 - 用
ws://localhost:8081握手失败:Socket.IO 服务器虽然监听了这个端口,但它不会响应原生 WebSocket 的握手请求——它只认自己的 Socket.IO 客户端发送的握手格式,所以连接会被直接关闭,抛出你看到的错误。
给你两个可行的解决办法:
办法一:让服务器同时支持标准 WebSocket
如果你想同时兼容 Socket.IO 客户端和 RxJS 的 WebSocketSubject,可以在现有 Socket.IO 服务器的基础上,再启动一个标准 WebSocket 服务(比如用 Node.js 的 ws 库),监听另一个端口或者同一个端口的不同路径。示例代码大概是这样:
// 现有 Socket.IO 服务器 const io = require('socket.io')(8081); io.on('connection', (socket) => { // 你的 Socket.IO 业务逻辑 }); // 新增标准 WebSocket 服务 const WebSocket = require('ws'); const wss = new WebSocket.Server({ port: 8082 }); wss.on('connection', (ws) => { ws.on('message', (data) => { // 处理标准 WebSocket 消息 ws.send(`Received: ${data}`); }); });
之后 RxJS 这边就可以用 ws://localhost:8082 正常连接了。
办法二:用 RxJS 封装 Socket.IO 客户端 API
如果不想改动服务器,那可以直接在客户端用 RxJS 来封装 Socket.IO 的事件,把它转换成 Observable 来使用,这样既保留了 Socket.IO 的功能,又能享受 RxJS 的操作符。示例代码:
import { Observable } from 'rxjs'; import io from 'socket.io-client'; // 初始化 Socket.IO 客户端 const socket = io('http://localhost:8081'); // 封装连接状态的 Observable const connectionStatus$ = new Observable(observer => { // 监听连接成功事件 socket.on('connect', () => observer.next('connected')); // 监听断开连接事件 socket.on('disconnect', () => observer.next('disconnected')); // 监听连接错误 socket.on('connect_error', (err) => observer.error(err)); // 订阅取消时断开 Socket.IO 连接 return () => socket.disconnect(); }); // 封装接收消息的 Observable const incomingMessages$ = new Observable(observer => { // 监听自定义消息事件(比如你的服务器发送的 'message' 事件) const handleMessage = (data) => observer.next(data); socket.on('message', handleMessage); // 订阅取消时移除事件监听 return () => socket.off('message', handleMessage); }); // 封装发送消息的方法 const sendMessage = (messageData) => { socket.emit('message', messageData); };
这样你就可以像使用普通 Observable 一样,用 connectionStatus$.subscribe(...)、incomingMessages$.pipe(...).subscribe(...) 来处理 Socket.IO 的事件了。
总结
记住:Socket.IO ≠ 标准 WebSocket,它是基于 WebSocket(或轮询)的一套自定义协议,所以不能直接用原生 WebSocket 或 RxJS 的 WebSocketSubject 去连接。选上面的任意一种办法,都能解决你的问题~
内容的提问来源于stack exchange,提问作者Picci

