记录一次connectSocket连接成功但onSocketOpen无法连接的问题

1. 发现问题

最近在写一个基于vue3+node.js+微信小程序的项目,这个项目用到了socket,通过编码和测试,后台(基于vue)可以正常访问服务器,并且连接上socket。

但是,在微信小程序端就出问题了。使用微信小程序原生的SocketTask技术,可以正常触发connectSocket的success回调,但无法执行onSocketOpen。

let SocketTask = wx.connectSocket({
    url: 'ws://localhost:4000',
    header: {
      'content-type': 'application/json'
    },
    query: {
      username: "abc"
    },
    protocols: ['protocol1'],
    method: "GET",
    success: function (res) {
      wx.onSocketOpen((result) => {
        console.log("连接成功");
      })
    }
})
SocketTask.onOpen(function (res) {
    console.log("已连接");
})

SocketTask.onError(function (err) {
    console.log("连接失败:", err);
})

SocketTask.onClose(function (res) {
    console.log('WebSocket连接已关闭!')
})

2. 解决过程

说实话,onSocketError回调的返回信息真是简单,就单单的“未完成的操作”六个字。问题到底出在哪个地方也不知道。

然后去试了weapp.socket.io,还是不行。又换了几个库,还是不行!

然后去查资料,关于这个问题的资料也是真的少,而且在论坛上大多是提问的,少有解决方法的。

而且这些解决方法对我来说也完全没用,包括修改ws协议、让服务器支持WSS的解决方案。

但有一个解答引起了我的注意,他说的是:socket的服务端版本可能与客户端版本不兼容!

3. 问题解决

这个说法让我想起了之前在socket.io官方文档上看到的版本兼容表格!

本能告诉我,困扰我两天的问题根源可能就出在这!

然后我去查微信小程序原生的SocketTask版本,没查到,去查了其他第三方库的版本,查到了但很模糊,基本没说兼容socket.io哪个版本。又去看了一下我服务端socket版本:4.7.5。

太高了,降服务器的socket版本吧?不可能,降不了一点!那就只能找适配服务端版本4.x的第三方库了。

找了半天也没找到。

然后我又去uni-app项目上测试socket,果然,通过uni-app原生的socket同样连接不了,跟小程序一样的问题。不过,倒是让我找到了适配uni-app的第三方socket库,并且这个还标注了兼容服务端4.x版本!

4. 第三方库

链接:@hyoga/uni-socket.io

一款适用于uni-app的socket.io封装,可用于uni-app、微信小程序的第三方库,兼容vue2、vue3,并且最关键的是兼容socket.io@4.x的版本!!

看到这个兼容表的时候,我真是感动到眼泪都要掉出来了。

然后赶紧根据官方文档去调试。

const socket = io('http://localhost:4000', {
	query: {},
	transports: ['websocket', 'polling'],
	timeout: 5000,
});

socket.on('connect', () => {
	// ws连接已建立,此时可以进行socket.io的事件监听或者数据发送操作
	// 连接建立后,本插件的功能已完成,接下来的操作参考socket.io官方客户端文档即可
	console.log('ws 已连接');
	// socket.io 唯一连接id,可以监控这个id实现点对点通讯
	const {
		id
	} = socket;
	socket.on(id, (message) => {
		// 收到服务器推送的消息,可以跟进自身业务进行操作
		console.log('ws 收到服务器消息:', message);
	});
	// 主动向服务器发送数据
		socket.emit('send_data', {
		time: +new Date(),
		});
	});

socket.on('error', (msg) => {
	console.log('ws error', msg);
});

果然,没报错!并且提示已连接。

服务端也成功输出连接信息

5. 总结

鬼知道看到服务端输出信息时我有多兴奋。

让我百思不得其解的问题,就是出在了socket.io服务端版本与客户端版本的不兼容上。(或许是吧)

对于4.x版本的socket.io,可以通过这个:@hyoga/uni-socket.io库去解决。

低于4.x版本的,就不知道还有其他哪些库可以用了。

// utils/websocket.js export default class WebSocketManager { constructor() { // WebSocket实例 this.ws = null; // 连接状态 this.readyState = { CONNECTING: 0, OPEN: 1, CLOSING: 2, CLOSED: 3 }; // 当前连接状态 this.state = this.readyState.CLOSED; // 房间ID this.roomId = ''; // 重连定时器 this.reconnectTimer = null; // 重连延迟(毫秒) this.reconnectDelay = 3000; // 最大重连延迟 2分钟内可以重连 this.maxReconnectDelay = 30000; // 重连次数 this.reconnectCount = 3; // 消息队列(连接断开时暂存消息) this.messageQueue = []; // 事件回调 this.callbacks = { onOpen: [], onMessage: [], onError: [], onClose: [] }; } // 连接WebSocket connect(roomId, wsUrl) { this.roomId = roomId; this.disconnect(); // 先断开已有的连接 try { // #ifdef H5 this.ws = new WebSocket(wsUrl); // #endif // #ifdef MP || APP-PLUS this.ws = uni.connectSocket({ url: wsUrl, success: (res) => { console.warn('connectSocket success', res) this.state = this.readyState.OPEN; this.triggerCallback('onOpen'); }, fail: (err) => { console.warn('connectSocket fail', err) this.triggerCallback('onError', err); } }); // #endif this.setupEventListeners(); this.state = this.readyState.CONNECTING; } catch (error) { this.triggerCallback('onError', error); this.startReconnect(); } } // 设置事件监听器 setupEventListeners() { if (!this.ws) return; // #ifdef H5 this.ws.onopen = () => { this.state = this.readyState.OPEN; this.reconnectCount = 0; this.reconnectDelay = 3000; this.triggerCallback('onOpen'); this.sendQueueMessages(); // 发送队列中的消息 }; this.ws.onmessage = (event) => { this.triggerCallback('onMessage', event.data); }; this.ws.onerror = (error) => { this.triggerCallback('onError', error); this.startReconnect(); }; this.ws.onclose = (event) => { this.state = this.readyState.CLOSED; this.triggerCallback('onClose', event); this.startReconnect(); }; // #endif // #ifdef MP || APP-PLUS uni.onSocketOpen((event) => { this.state = this.readyState.OPEN; this.reconnectCount = 0; this.reconnectDelay = 3000; this.triggerCallback('onOpen'); this.sendQueueMessages(); }); uni.onSocketMessage((event) => { this.triggerCallback('onMessage', event.data); }); uni.onSocketError((event) => { this.triggerCallback('onError', event); this.startReconnect(); }); uni.onSocketClose((event) => { this.state = this.readyState.CLOSED; this.triggerCallback('onClose', event); this.startReconnect(); }); // #endif } // 发送消息 send(message) { if (this.state !== this.readyState.OPEN) { this.messageQueue.push(message); this.startReconnect(); return; } try { // #ifdef H5 this.ws.send(typeof message === 'object' ? JSON.stringify(message) : message); // #endif // #ifdef MP || APP-PLUS uni.sendSocketMessage({ data: typeof message === 'object' ? JSON.stringify(message) : message }); // #endif } catch (error) { this.triggerCallback('onError', error); this.messageQueue.push(message); this.startReconnect(); } } // 发送队列中的消息 sendQueueMessages() { while (this.messageQueue.length > 0) { const message = this.messageQueue.shift(); this.send(message); } } // 断开连接 disconnect() { clearTimeout(this.reconnectTimer); if (this.ws) { // #ifdef H5 this.ws.close(); // #endif // #ifdef MP || APP-PLUS uni.closeSocket(); // #endif this.ws = null; } this.state = this.readyState.CLOSED; } // 开始重连 startReconnect() { clearTimeout(this.reconnectTimer); this.reconnectCount++; // 指数退避重连策略 this.reconnectDelay = Math.min( this.maxReconnectDelay, this.reconnectDelay * 2 ); this.reconnectTimer = setTimeout(() => { this.connect(this.roomId, this.getBaseWsUrl()); }, this.reconnectDelay); } getBaseWsUrl() { if (!this.ws || !this.ws.url) return ''; if (!this.baseWsUrl) { this.baseWsUrl = this.wsUrl || '' } return this.baseWsUrl; } // 注册事件回调 on(event, callback) { if (this.callbacks[event]) { this.callbacks[event].push(callback); } } // 触发事件回调 triggerCallback(event, data = {}) { if (this.callbacks[event]) { this.callbacks[event].forEach(callback => { callback(data); }); } } // 离开房间并断开连接 leaveRoom() { this.disconnect(); this.roomId = ''; } } 优化这个wenbscket封装 其实h5都可以用uniapp提供的链接方式吧 统一一下
08-03
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值