如何用Node.js的ws包连接Socket.io第三方服务器?
如何用ws包连接Socket.io服务器
嘿,这个问题我之前踩过坑!Socket.io可不是标准的WebSocket实现——它在原生WebSocket协议之上封装了自己的握手流程、心跳机制和消息格式,所以直接用ws包连默认的端点肯定会失败。咱们一步步来搞定它:
核心原因
Socket.io客户端和服务器之间会先通过HTTP请求完成握手,获取会话ID(sid),然后才会升级到WebSocket连接,而且连接URL需要带上特定的查询参数,还得遵循它的消息格式规范。
具体实现步骤
1. 先完成Socket.io握手,获取会话ID
你需要先发送一个HTTP GET请求到Socket.io的端点,带上EIO(版本号)和transport=polling的参数,从响应里提取出sid。
2. 用ws包连接正确的WebSocket URL
连接的URL格式应该是:
wss://api.example.com/1.0/scores/?EIO=4&transport=websocket&sid=你的会话ID
注意:EIO的版本要对应服务器的Socket.io版本,v4用EIO=4,v3用EIO=3,v2用EIO=2,版本不匹配会握手失败。
3. 处理Socket.io的初始化消息
连接成功后,Socket.io要求你先发送2probe,服务器会回复3probe,之后你发送5表示准备就绪,这样就能正常收发消息了。另外,Socket.io的消息都有前缀(比如42表示事件消息,2表示ping),需要解析前缀后的内容。
完整代码示例
const WebSocket = require('ws'); const fetch = require('node-fetch'); // 也可以用http模块替代 async function connectToSocketIoServer() { // 第一步:获取会话ID(sid) const handshakeUrl = 'https://api.example.com/1.0/scores/?EIO=4&transport=polling'; const handshakeResponse = await fetch(handshakeUrl); const rawHandshakeData = await handshakeResponse.text(); // 解析响应中的sid,响应格式类似:"0{"sid":"abc123","upgrades":["websocket"],...}" const sidMatch = rawHandshakeData.match(/"sid":"([^"]+)"/); if (!sidMatch) { throw new Error('无法从握手响应中获取会话ID'); } const sid = sidMatch[1]; // 第二步:建立WebSocket连接 const wsUrl = `wss://api.example.com/1.0/scores/?EIO=4&transport=websocket&sid=${sid}`; const wsClient = new WebSocket(wsUrl); wsClient.on('open', () => { console.log('WebSocket已连接到Socket.io服务器'); // 发送初始化probe消息 wsClient.send('2probe'); }); wsClient.on('message', (data) => { const message = data.toString(); console.log('收到消息:', message); // 处理probe回复 if (message === '3probe') { wsClient.send('5'); console.log('已发送就绪消息'); } // 处理心跳ping,回复pong else if (message === '2') { wsClient.send('3'); } // 处理事件消息(42开头) else if (message.startsWith('42')) { const [eventName, eventData] = JSON.parse(message.slice(2)); console.log(`收到事件 ${eventName}:`, eventData); // 这里可以根据业务逻辑处理事件 } }); wsClient.on('error', (error) => { console.error('WebSocket错误:', error); }); wsClient.on('close', () => { console.log('WebSocket连接已关闭'); }); } // 执行连接 connectToSocketIoServer().catch(console.error);
额外注意事项
- 一定要匹配正确的
EIO版本:可以通过查看服务器返回的HTTP响应头或者Socket.io文档确认版本。 - 心跳处理:Socket.io会定期发送
2(ping),你必须回复3(pong),否则服务器会主动断开连接。 - 消息格式:所有事件消息都是
42[事件名, 数据]的格式,需要去掉前缀42后再解析JSON。
内容的提问来源于stack exchange,提问作者Orbit
相关产品推荐
相关产品推荐

