解决sockjs、stomp在uni-app端使用的坑
<p><span style="font-size: 16px"> 我们项目之前前后端使用的是Stomp + SockJs实现的在线直播的实时聊天,现在需要搬到app上,所以要在uni-app上面也实现一次,结果就很自然的出问题了。下面整理一下在uniapp整合WebSocket中遇到的bug。</span></p><p><span style="font-size: 16px">1、第一次尝试</span></p>
<p><span style="font-size: 16px"> 先像web开发一样去写:先引入stomjs和sockjs包,然后用 new SockJS(url) 的方式去实例化SockJs,然后通过创建StompClient去连接订阅。</span></p>
<p><span style="font-size: 16px"> H5时连接没有任何问题,但换到uni-app的时候问题就来了,sockjs.js里面用了一点操作DOM元素的方法,比如<code>document.getElementsByTagName</code>,uni-app是解析不了的,原生的微信小程序好像也解析不了。</span></p>
<p><span style="font-size: 16px">2、第二次尝试</span></p>
<p><span style="font-size: 16px"> 这次放弃了使用外部的js,采用原生的uni.connectSocket()的方式创建连接。</span></p>
<div class="cnblogs_code">
<pre><span style="font-size: 16px">SocketTask =<span style="color: rgba(0, 0, 0, 1)"> uni.connectSocket({</span>
url: <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">http://***:8081/socket</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 0, 1)"> //</span><span style="color: rgba(0, 128, 0, 1)">url: 'ws:</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">localhost:8081/socket',</span>
data: <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">data</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">,
header: {
</span><span style="color: rgba(128, 0, 0, 1)"> '</span><span style="color: rgba(128, 0, 0, 1)">content-type</span><span style="color: rgba(128, 0, 0, 1)">'</span>: <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">application/json</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">
},
method: </span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">post</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">,
success: function(res) {
console.log(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">WebSocket连接创建</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">, res)
},
fail: function(err) {
uni.showToast({
title: </span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">网络异常!</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">,
})
console.log(err)
},
})</span></span></pre>
</div>
<p><span style="font-size: 16px"> 代码中显示的就很清楚了,uni-app连接websocket的时候要是用ws或者wss,相当于http和https,不然就会报无效的url这种异常,但是这个时候还是会抛异常:Error during WebSocket handshake: Unexpected response code: 200</span></p>
<p><span style="font-size: 16px"> 其中遇到的问题就是使用原生websocket怎么也连不上的问题,后来就查看服务端是如何处理sockjs的。然后我就拉取了后端代码,去后端代码里最好找到了问题的关键,先贴一下服务端配置:</span></p>
<div class="cnblogs_code">
<pre><span style="font-size: 16px"><span style="color: rgba(0, 0, 0, 1)"> @Override
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">用来注册Endpoint,“/event-websocket”即为客户端尝试建立连接的地址。</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> registerStompEndpoints(StompEndpointRegistry registry) {
registry
.addEndpoint(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/event-websocket</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
.setAllowedOrigins(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">*</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
.withSockJS();
}</span></span></pre>
</div>
<p><span style="font-size: 16px"> 可以看到服务端是开启了sockjs模式的,将此处的withSockJS()去除,就可以通过原生方式连接了。因为sockjs在浏览器不支持wobsoket请求是会自动切换为http请求轮训方式。</span></p>
<p><span style="font-size: 16px"> 但是去除withSockJS(),那么web就无法连接了,怎么办呢?可以注册建立2个链接地址,一个给web使用sockjs模式,另一个给app使用,不使用sockjs模式。</span></p>
<div class="cnblogs_code">
<pre><span style="font-size: 16px"><span style="color: rgba(0, 0, 0, 1)"> @Override
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">用来注册Endpoint,“/event-websocket”即为客户端尝试建立连接的地址。</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> registerStompEndpoints(StompEndpointRegistry registry) {
registry
.addEndpoint(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/event-websocket</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
.setAllowedOrigins(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">*</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
.withSockJS();
registry
.addEndpoint(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/event-websocket-app</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
.setAllowedOrigins(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">*</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}</span></span></pre>
</div>
<p><span style="font-size: 16px">3、第3次尝试</span></p>
<p><span style="font-size: 16px"> 经过上述处理,以为万事大吉了,但是结果在安卓app上是可以正常建立链接的,但是在ios app上却不行,百思不得解,最后解决方式是将域名模式改成ip模式就可以了</span></p>
<div class="cnblogs_code">
<pre><span style="font-size: 16px"><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 连接后台</span>
<span style="color: rgba(0, 0, 0, 1)">initSocket () {
let that </span>= <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">
let _unitoken </span>= uni.getStorageSync(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">token</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
let _token </span>= _unitoken ? _unitoken.substring(<span style="color: rgba(128, 0, 128, 1)">7</span>) : <span style="color: rgba(128, 0, 0, 1)">''</span>
<span style="color: rgba(0, 128, 0, 1)"> //</span><span style="color: rgba(0, 128, 0, 1)"> 当未登录或登录失效时后台根据_randomUserId模拟匿名用户</span>
let _randomUserId = (-generateRandom(<span style="color: rgba(128, 0, 128, 1)">100000</span><span style="color: rgba(0, 0, 0, 1)">))
let _eventId </span>= <span style="color: rgba(0, 0, 255, 1)">this</span>.<span style="color: rgba(0, 0, 255, 1)">params</span><span style="color: rgba(0, 0, 0, 1)">.eventId
let sockUrl </span>= wsdomain + `<span style="color: rgba(0, 0, 255, 1)">event</span>-websocket-app?eventId=${_eventId}&token=${_token}&userId=<span style="color: rgba(0, 0, 0, 1)">${_randomUserId}`
let socket </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> UniWebSocket(sockUrl)
</span><span style="color: rgba(0, 0, 255, 1)"> this</span>.stompClient =<span style="color: rgba(0, 0, 0, 1)"> Stomp.over(socket)
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.stompClient.connect({}, (res) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 订阅服务端提供的某个topic</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.stompClient.subscribe(`/topic/<span style="color: rgba(0, 0, 255, 1)">event</span>/${_eventId}`, (frame) =><span style="color: rgba(0, 0, 0, 1)"> {
that.addBarage(JSON.parse(frame.body))
})
that.sentFirst()
}, (err) </span>=><span style="color: rgba(0, 0, 0, 1)"> {
console.log(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">失败:</span><span style="color: rgba(128, 0, 0, 1)">'</span> +<span style="color: rgba(0, 0, 0, 1)"> err)
</span><span style="color: rgba(0, 0, 255, 1)"> if</span> (<span style="color: rgba(0, 0, 255, 1)">this</span>.infoCount > <span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">) {
let _speaker </span>= <span style="color: rgba(0, 0, 255, 1)">this</span>.<span style="color: rgba(0, 0, 255, 1)">event</span>.currentAgendaSpeaker ||<span style="color: rgba(0, 0, 0, 1)"> {}
let _tip </span>=<span style="color: rgba(0, 0, 0, 1)"> {
headimgurl: _speaker.icon,
name: _speaker.name,
text: </span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">温馨提示:您的连接已断开,将无法收到聊天信息,请退出直播间重新进入。</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">
}
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.infoFlow.push(_tip)
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.infoCount = <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">
}
</span><span style="color: rgba(0, 0, 255, 1)"> if</span> (!<span style="color: rgba(0, 0, 255, 1)">this</span>.timer) <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.resetWebSocket()
</span><span style="color: rgba(0, 0, 255, 1)">else</span> clearInterval(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.timer)
})
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.stompClient.debug = <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">
},</span></span></pre>
</div>
<p><span style="font-size: 16px"> wsdomain由原域名形式换成ip形式就可以了。</span></p>
<div class="cnblogs_code">
<pre><span style="font-size: 16px">wss:<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">dev.modb.pro/ws/</span>
<span style="color: rgba(0, 0, 0, 1)">
ws:</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">服务器ip:8080/</span></span></pre>
</div>
<p> </p><br><br>
来源:https://www.cnblogs.com/goloving/p/14734630.html
頁:
[1]