NestJS集成Socket.io对接币安WebSocket 前端仅收首条数据排查
问题核心原因
- Socket.io 的
emit回调是单次响应机制:前端调用socket.emit('events', '', 回调)时,传入的回调仅会接收服务端返回的一次确认响应,就算后端 Observable 持续产生数据,这个回调也只会触发一次。 - NestJS
@SubscribeMessage装饰器默认逻辑:如果处理函数返回 Observable,默认仅会把第一个next产生的值作为响应返回给emit的回调,后续的next值不会主动推送给前端,需要手动调用推送方法才能下发。 - 币安连接重复创建:当前每次客户端触发
events事件都会新建一个币安 WebSocket 连接,并发高后会触发币安连接数限制,也会造成资源浪费。
修复方案
后端修改(Coin.gateway.ts)
调整为服务启动时仅初始化一次币安连接,收到币安推送的数据后主动通过 Socket.io 广播给所有客户端:
import { MessageBody, SubscribeMessage, WebSocketGateway, WebSocketServer, OnGatewayInit } from '@nestjs/websockets'; import { Server } from 'socket.io'; import { Coin } from './classes/coin'; import * as coinlist from './list/coins.json' @WebSocketGateway(811, {transports: ['websocket', 'polling'], cors: true}) export class CoinGateway implements OnGatewayInit { @WebSocketServer() server: Server; private coins: Coin; // 网关初始化完成后自动执行,仅执行一次 afterInit() { this.coins = new Coin(coinlist, 'usdt', 'miniTicker') // 订阅币安数据流,收到数据后主动推送给所有客户端 this.coins.getCryptoData().subscribe((c) => { this.server.emit('coinData', c) }) } @SubscribeMessage('events') handleMessage(@MessageBody() data: any) { // 仅返回单次订阅确认,持续数据通过上面的主动推送下发 return {msg: '订阅成功'} } }
前端修改(useEffect 逻辑)
新增对服务端主动推送事件的监听,不要依赖 emit 回调接收持续数据:
useEffect(() => { const socket = io('ws://localhost:811', {transports: ['websocket']}) socket.on('connect', () => { console.log('Connection established from client') socket.emit('events', '', (res: any) => { console.log('订阅确认', res) }) // 监听服务端主动推送的币安数据,每次推送都会触发 socket.on('coinData', (data) => { console.log('收到币安数据', data) }) const engine = socket.io.engine; console.log(engine.transport.name); engine.once("upgrade", () => { console.log(engine.transport.name); }); engine.on("packetCreate", ({ type, data }) => { console.log('Stype', type) console.log('Sdata', data) }); }) // 组件卸载时主动断开连接,避免内存泄漏 return () => { socket.disconnect() } }, [])
额外Bug修复
Coin.ts 构造函数拼接币安连接url时,模板字符串末尾多了换行符,会导致连接请求异常,需要调整:
// 原来的错误写法 return `${c.symbol.toLowerCase()}${pair}@${method} // 修改后 return `${c.symbol.toLowerCase()}${pair}@${method}`
内容的提问来源于stack exchange,提问作者Timur
相关产品推荐
相关产品推荐

