最近在开发一个基于websocket的实时语音转文字小工具【就是这个】,出现了一个奇怪的现象:
前端代码
import { io } from 'socket.io-client';
...
await this.connectWebSocket();
...
connectWebSocket() {
return new Promise((resolve, reject) => {
this.socket = io('ws://localhost:8080', {
path: '/ws',
transports: ['websocket'],
auth: {
token: '11223333'
},
});
this.socket.on('connect', () => {
console.log('WebSocket连接成功');
this.status = '已连接服务器,正在录音...';
});
this.socket.on('disconnect', () => {
console.log('WebSocket断开连接');
this.status = '服务器连接已断开';
});
this.socket.on('transcript', (data) => {
console.log('收到转写结果:', data);
this.processTranscript(data);
});
this.socket.on('error', (error) => {
console.error('WebSocket错误:', error);
this.status = `连接错误: ${error.message}`;
});
});
},
H5页面现象
后端日志:
21:48:33.774 [nioEventLoopGroup-2-1] INFO i.n.handler.logging.LoggingHandler - [id: 0xc034c3bc, L:/[0:0:0:0:0:0:0:0]:8080] READ: [id: 0xc4e5890d, L:/[0:0:0:0:0:0:0:1]:8080 - R:/[0:0:0:0:0:0:0:1]:50069]
21:48:33.777 [nioEventLoopGroup-2-1] INFO i.n.handler.logging.LoggingHandler - [id: 0xc034c3bc, L:/[0:0:0:0:0:0:0:0]:8080] READ COMPLETE
21:48:34.218 [nioEventLoopGroup-2-1] INFO i.n.handler.logging.LoggingHandler - [id: 0xc034c3bc, L:/[0:0:0:0:0:0:0:0]:8080] READ: [id: 0x4170a495, L:/127.0.0.1:8080 - R:/127.0.0.1:50072]
21:48:34.219 [nioEventLoopGroup-2-1] INFO i.n.handler.logging.LoggingHandler - [id: 0xc034c3bc, L:/[0:0:0:0:0:0:0:0]:8080] READ COMPLETE
核心原因:
前端 使用的是 Socket.IO 协议(基于 Engine.IO,带
EIO=4
参数)。后端 实现的是 原生 WebSocket(通过 Netty 的
WebSocketServerProtocolHandler
)。这两者 协议不兼容,Socket.IO 客户端无法直接连接原生 WebSocket 服务。
修改方案
特性 | Socket.IO | 原生 WebSocket |
---|---|---|
协议 | 基于 Engine.IO,封装了 WebSocket + HTTP 长轮询 | 纯 WebSocket(RFC 6455) |
兼容性 | 自动降级兼容旧浏览器(IE9+) | 仅支持现代浏览器(IE10+) |
功能扩展 | 内置房间、广播、自动重连、ACK 确认等 | 需手动实现 |
数据传输 | 支持二进制(需配置)和结构化数据(JSON) | 直接支持二进制和文本 |
连接复杂度 | 高(握手阶段较长) | 低(直接建立 WS 连接) |
适用场景 | 实时性要求高、需复杂功能(如聊天室) | 轻量级、低延迟(如音频流、游戏) |
我经过权衡后决定使用原生的WebSocket
修改后的H5代码如下:
connectWebSocket() {
return new Promise((resolve, reject) => {
const ws = new WebSocket('ws://localhost:8080/ws');
ws.onopen = () => {
console.log('WebSocket连接成功');
this.status = '已连接服务器,正在录音...';
this.socket = ws;
resolve(); // ✅ 必须 resolve,才能继续录音
};
ws.onclose = () => {
console.log('WebSocket断开连接');
this.status = '服务器连接已断开';
};
ws.onmessage = (event) => {
console.log('收到转写结果:', event.data);
this.processTranscript(event.data);
};
ws.onerror = (error) => {
console.error('WebSocket错误:', error);
this.status = '连接错误';
reject(error);
};
});
},
完美运行!