解决sockjs、stomp在uni-app端使用的坑
我们项目之前前后端使用的是Stomp + SockJs实现的在线直播的实时聊天,现在需要搬到app上,所以要在uni-app上面也实现一次,结果就很自然的出问题了。下面整理一下在uniapp整合WebSocket中遇到的bug。
1、第一次尝试
先像web开发一样去写:先引入stomjs和sockjs包,然后用 new SockJS(url) 的方式去实例化SockJs,然后通过创建StompClient去连接订阅。
H5时连接没有任何问题,但换到uni-app的时候问题就来了,sockjs.js里面用了一点操作DOM元素的方法,比如document.getElementsByTagName
,uni-app是解析不了的,原生的微信小程序好像也解析不了。
2、第二次尝试
这次放弃了使用外部的js,采用原生的uni.connectSocket()的方式创建连接。
SocketTask = uni.connectSocket({
url: 'http://***:8081/socket',
//url: 'ws://localhost:8081/socket',
data: 'data',
header: {
'content-type': 'application/json'
},
method: 'post',
success: function(res) {
console.log('WebSocket连接创建', res)
},
fail: function(err) {
uni.showToast({
title: '网络异常!',
})
console.log(err)
},
})
代码中显示的就很清楚了,uni-app连接websocket的时候要是用ws或者wss,相当于http和https,不然就会报无效的url这种异常,但是这个时候还是会抛异常:Error during WebSocket handshake: Unexpected response code: 200
其中遇到的问题就是使用原生websocket怎么也连不上的问题,后来就查看服务端是如何处理sockjs的。然后我就拉取了后端代码,去后端代码里最好找到了问题的关键,先贴一下服务端配置:
@Override
//用来注册Endpoint,“/event-websocket”即为客户端尝试建立连接的地址。
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry
.addEndpoint("/event-websocket")
.setAllowedOrigins("*")
.withSockJS();
}
可以看到服务端是开启了sockjs模式的,将此处的withSockJS()去除,就可以通过原生方式连接了。因为sockjs在浏览器不支持wobsoket请求是会自动切换为http请求轮训方式。
但是去除withSockJS(),那么web就无法连接了,怎么办呢?可以注册建立2个链接地址,一个给web使用sockjs模式,另一个给app使用,不使用sockjs模式。
@Override
//用来注册Endpoint,“/event-websocket”即为客户端尝试建立连接的地址。
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry
.addEndpoint("/event-websocket")
.setAllowedOrigins("*")
.withSockJS();
registry
.addEndpoint("/event-websocket-app")
.setAllowedOrigins("*");
}
3、第3次尝试
经过上述处理,以为万事大吉了,但是结果在安卓app上是可以正常建立链接的,但是在ios app上却不行,百思不得解,最后解决方式是将域名模式改成ip模式就可以了
// 连接后台
initSocket () {
let that = this
let _unitoken = uni.getStorageSync('token')
let _token = _unitoken ? _unitoken.substring(7) : ''
// 当未登录或登录失效时后台根据_randomUserId模拟匿名用户
let _randomUserId = (-generateRandom(100000))
let _eventId = this.params.eventId
let sockUrl = wsdomain + `event-websocket-app?eventId=${_eventId}&token=${_token}&userId=${_randomUserId}`
let socket = new UniWebSocket(sockUrl)
this.stompClient = Stomp.over(socket)
this.stompClient.connect({}, (res) => {
// 订阅服务端提供的某个topic
this.stompClient.subscribe(`/topic/event/${_eventId}`, (frame) => {
that.addBarage(JSON.parse(frame.body))
})
that.sentFirst()
}, (err) => {
console.log('失败:' + err)
if (this.infoCount > 5) {
let _speaker = this.event.currentAgendaSpeaker || {}
let _tip = {
headimgurl: _speaker.icon,
name: _speaker.name,
text: '温馨提示:您的连接已断开,将无法收到聊天信息,请退出直播间重新进入。'
}
this.infoFlow.push(_tip)
this.infoCount = 0
}
if (!this.timer) this.resetWebSocket()
else clearInterval(this.timer)
})
this.stompClient.debug = null
},
wsdomain由原域名形式换成ip形式就可以了。
wss://dev.modb.pro/ws/
ws://服务器ip:8080/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
2018-05-06 Node.js:创建应用+回调函数(阻塞/非阻塞)+事件循环