Socket.IO v2.4.1服务端向指定客户端emit如何判断发送成败
Socket.IO ^2.4.1 服务端向指定客户端发消息并获取送达状态解决方案
报错根因说明
- 错误1原因:Socket.IO 2.x版本的
emit方法原生不返回Promise对象,因此不支持.then()调用和await语法,强行调用就会报then is not a function错误。 - 错误2原因:
socket.to(xxx).emit()属于广播类调用,Socket.IO 2.x版本明确禁止广播模式下使用回调函数,因此触发Callbacks are not supported when broadcasting错误。
可行实现方案
方案1:维护在线socket实例映射,直接调用目标socket的emit方法
Socket.IO 2.x仅支持单个socket实例直接调用emit时传入回调,你可以提前存储所有在线用户的socket实例,发消息时直接取目标实例调用即可:
- 服务端全局存储在线socket实例
// 全局存储,key为socket id,value为对应socket实例 const onlineSocketMap = {} io.on('connection', socket => { // 用户连接时存入映射 onlineSocketMap[socket.id] = socket // 用户断开时删除映射 socket.on('disconnect', () => { delete onlineSocketMap[socket.id] }) })
- 调整业务逻辑代码
async function packet_from_client(socket,packet) { var json_msg = JSON.parse(packet); var user_receiver = await search_userby_user_id(json_msg.user_id_receiver); if (user_receiver.length > 0) { const targetSocketId = user_receiver[0].socket_id const targetSocket = onlineSocketMap[targetSocketId] // 先判断目标用户是否在线 if (!targetSocket) { console.log('目标用户不在线,发送失败') return } // 直接调用目标socket的emit方法,传入回调 targetSocket.emit("from_server", packet, function(ackData) { // 回调触发即代表客户端已收到消息,ackData为客户端回传的确认信息 console.log('消息送达成功,客户端返回:', ackData) }) } }
- 客户端增加确认回调逻辑
// 客户端监听服务端消息,收到后执行回调通知服务端 socket.on('from_server', (packet, callback) => { // 处理自身业务逻辑 // 执行回调回传确认信息,可自定义返回内容 callback('收到消息') })
方案2:自定义消息确认机制
如果不想维护全局socket映射,可以自己实现ACK确认逻辑:
- 服务端发送消息时给每个消息生成唯一
msg_id,本地存储待确认的消息列表,设置超时时间 - 客户端收到消息后,主动向服务端发送
ack事件,携带对应msg_id - 服务端收到
ack事件后标记对应消息已送达,超时未收到ack则判定为发送失败
内容的提问来源于stack exchange,提问作者mamena tech
相关产品推荐
相关产品推荐

