Android Kotlin使用Socket.io时chat:enter事件收不到服务端ack
问题现象
已成功实现客户端与服务端的Socket.io连接,但存在异常:
chat:enter事件在前端环境下运行正常,可正常收到服务端ack确认- 仅Android Kotlin实现中无法收到该事件的服务端应答
相关实现代码如下:
Socket连接相关实现
fun connectWithChatServer(message: Message, onSocketIOEventListener: Listeners.OnSocketIOEventListener) { try { if (message.chatConnectionInfo != null) { val token: String = message.chatConnectionInfo?.token!! try { val opts = IO.Options() opts.forceNew = true opts.query = "{token : '$token'}" opts.transports = arrayOf("websocket") opts.path = "/chatsignal" mSocket = IO.socket(message.chatConnectionInfo?.connectionUrl.toString(), opts) makeConnection() } catch (e: Exception) { e.printStackTrace() Log.d("fail", "Failed to connect") } } } catch (e: URISyntaxException) { throw RuntimeException(e) } } private fun makeConnection() { if (mSocket != null) { mSocket?.connect() registerConnectionAttributes() } } private fun registerConnectionAttributes() { try { if (mSocket != null) { mSocket?.on(Socket.EVENT_CONNECT, onConnect) } } catch (e: java.lang.Exception) { e.printStackTrace() } }
onConnect事件发送逻辑
private var onConnect = Emitter.Listener { mSocket!!.emit("chat:enter", "{}", Ack { args -> Constants.printDebug(logTag, "Ack ${args[0]}") val text = args[0].toString() }) }
问题原因与修复方案
该问题由两个核心代码错误导致:
- query参数格式不符合规范
当前代码中opts.query = "{token : '$token'}"传入的是JSON格式字符串,Socket.io客户端要求query参数必须为标准URL查询字符串格式(即key=value形式),错误的参数格式会导致服务端鉴权逻辑异常,部分事件处理流程无法正常触发。
直接将该行修改为:
opts.query = "token=$token"
- 监听器注册顺序错误 + 传参类型不匹配
- 当前逻辑先调用
mSocket?.connect()再注册EVENT_CONNECT监听器,极端场景下连接成功事件会在监听器绑定前触发,导致onConnect逻辑根本没有执行 - emit事件时传入的
"{}"是字符串类型,和前端传入的空JSON对象类型不一致,多数服务端框架会因参数类型校验不通过,不返回ack响应
对应修复方式:
- 调整执行顺序,先注册所有事件监听器,再发起连接
- 使用原生
JSONObject传递空参数对象,保证和前端传参类型一致
修复后的相关代码如下:
// 调整连接方法逻辑,先绑监听器再连接 private fun makeConnection() { if (mSocket != null) { registerConnectionAttributes() mSocket?.connect() } } // 修改emit传参类型 private var onConnect = Emitter.Listener { val emptyParams = org.json.JSONObject() mSocket!!.emit("chat:enter", emptyParams, Ack { args -> Constants.printDebug(logTag, "Ack ${args[0]}") val text = args[0].toString() }) }
额外排查项
- 确认Android端使用的Socket.io客户端版本和服务端部署的Socket.io大版本完全一致,跨大版本会存在事件、ack的协议兼容问题
- 补充绑定
Socket.EVENT_CONNECT_ERROR、Socket.EVENT_ERROR事件监听器,打印错误日志排查是否存在隐式鉴权、连接异常
内容的提问来源于stack exchange,提问作者Ahmad Bhatti
相关产品推荐
相关产品推荐

