我先是使用的Stomp over WebSocket实现了一次消息推送。然后心血来潮想要在uni-app上面也实现一次。(uni-app是基于Vue.JS的)结果就很自然的出问题了。下面整理一下在uniapp整合WebSocket中遇到的bug
因为我没有什么小程序的底子,我先想当然的像web开发一样去写。先引入stomJS和sockJS包,然后用new Socket(url)的方式去实例化SockJs,然后通过创建StompClient去连接订阅。
connect: function(userId,txtNumber, successCallback) {
var socket = new SockJS(sprintf("http://%s:8081/socket", serverIp));//实例化sockJS
page.stompClient = Stomp.over(socket);//实例化STOMP
var headers = {
"passcode" : "343",
"login": userId,
"chatNumber":txtNumber
};
//stompClient.debug = null;
page.stompClient.connect(headers, function(response) {//连接客户端
successCallback(response);//;连接成功时
}, function(disconnectedMessage){//连接失败时
console.log(disconnectedMessage);
});
},
bindEvent: function() {
$("#btnJoin").on("click", function() {
var userId = $("#txtName").val();
var txtNumber = $("#txtNumber").val();
page.connect(userId, txtNumber,function(response){
$(".loginDiv").hide();
$(".container").show();
var users = JSON.parse(response.body);
$.each(users, function(index, user){
page.renderUser(user);
});
// emphasize current user
page.$userList.find("#" + userId).find("h5").css("font-weight", "bold").css("font-style", "italic")
var channel = "/topic/chat".concat(ChannelType.NEW_MESSAGE).concat("/"+txtNumber);
page.stompClient.subscribe(channel, function(response){
var msg = JSON.parse(response.body);
page.renderMessage(msg)
});
var channel = "/topic/chat".concat(ChannelType.NEW_USER).concat("/"+txtNumber);
page.stompClient.subscribe(channel, function(response){
var user = JSON.parse(response.body);
page.renderUser(user);
console.log(user);
});
var channel = "/topic/chat".concat(ChannelType.OFFLINE).concat("/"+txtNumber);
page.stompClient.subscribe(channel, function(response){
var user = JSON.parse(response.body);
page.removeUser(user);
});
})
});
$("#btnSend").on("click", function(){
var txtNumber = $("#txtNumber").val();
var $txtMessage = $("#txtMessage");
var msg = $txtMessage.val();
$txtMessage.val("");
page.stompClient.send("/app/chat", {}, JSON.stringify({"message": msg,"chatNumber":txtNumber}));
});
},
renderMessage: function(msg) {
var $msgModel = page.$msgModel.clone();
$msgModel.find(".lblMsg").text(msg.message);
$msgModel.find(".lblUser").text(msg.sender);
page.$msgList.append($msgModel);
},
renderUser: function(user) {
var $userModel = page.$userModel.clone();
$userModel.prop("id", user.userId);
$userModel.find(".lblUser").text(user.userId);
page.$userList.append($userModel);
},
removeUser: function(user) {
page.$userList.find("#" + user.userId).remove();
}
};
$(document).ready(function(){
page.init();
window.onbeforeunload = function (event) {
// demonstrate before closing browser,
// no need to call this, disconnect is called when tab/browser is close
if(page.stompClient != null) {
page.stompClient.disconnect();
}
};
})
这里只展示了部分关键代码。H5是连接没有任何问题,但换到uni-app的时候问题就来了,sockjs.js里面用了一点操作DOM元素的方法,比如document.getElementsByTagName
,uni-app是解析不了的,原生的微信小程序好像也解析不了?这我没有去试验过。反正H5的方式算是崩了。
这次放弃了使用外部的js,采用原生的uni.connectSocket()的方式创建连接。
SocketTask = uni.connectSocket({
//192.28.182.150
url: 'http://192.28.182.150:8081/socket',
//url: 'ws://localhost:8081/socket',
data: 'data',
header: {
'content-type': 'application/json',
"passcode": "343",
"login": 1,
"chatNumber": 1
},
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
网上查了很多博客帖子大多说是拦截器的问题。但是检查了我的服务端代码,发现是没有问题的,最后找到了问题的关键。先贴一下服务端配置
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/socket").setAllowedOrigins("*")
.addInterceptors(new ConnectionInterceptor()).withSockJS();
}
我服务端是开启了sockjs模式的。将此处的withSockJS()去除,就可以通过原生方式连接了,因为soketjs在浏览器不支持wobsoket请求是会自动切换为http请求轮训方式。结果就挂了。以前一直做后端,第一次玩这个东西踩了很多坑。好在最后都一一解决了。感谢度娘。