微信小程序使用STOMP(WebSocket)
小程序的WebSocket API跟一般瀏覽器的有點差別,存在一些限制。本文主要涉及小程序使用STOMP時注意事項。
基礎
-
小程序需要維護兩個狀態:
- 微信服務器登錄狀態
- 第三方(即我們自己服務器)的登錄狀態
-
小程序使有wx.request()來發起請求,使用wx.connectSocket()創建WebSocket連接
- wx.request()不會自動加上cookie來,可以自己加cookie到header或使用其他session標識
- wx.connectSocket()跟wx.request()類似,handshake時加上session標識
-
真實環境需要在微信平台預設相關域名,必須使用TLS,即使用https、wss協議。開發調試時可以不限制。
使用STOMP與WebSocket遇到的問題
問題1: 連接成功后,很快自動斷開
因為剛開始使用STOMP時,同事在網上找到以下代碼。出現問題我打開代碼看了一下,剛看到肯定都覺得兩個空方法很奇怪,原來不寫會報錯。打開stomp.js一看,很快找到原因,setInterval是用來發心跳包的,而小程序沒有window對象。
網絡文章
var Stomp = require('../../utils/stomp.js').Stomp;
Stomp.setInterval = function () { }
Stomp.clearInterval = function () { }
var client = Stomp.over(ws);
stomp.js部分源碼
if (typeof window !== "undefined" && window !== null) {
Stomp.setInterval = function (interval, f) {
return window.setInterval(f, interval);
};
Stomp.clearInterval = function (id) {
return window.clearInterval(id);
};
window.Stomp = Stomp;
} else if (!exports) {
self.Stomp = Stomp;
}
解決辦法
Stomp.setInterval = function (interval, f) {
return setInterval(f, interval);
};
Stomp.clearInterval = function (id) {
return clearInterval(id);
};
問題2: 電腦開發時連接正常,手機遠程調試時連接失敗
一開始 返回 401 UNAUTHORIZED,后來看到client日志提示draft handshake refused。
逐步排除 域名限制、TLS證書有效性、Nginx配置、跨域問題。本應該先關注 401狀態碼的,通過服務器日志與后台調試,發現問題所在:client發起連接時沒有在代碼加上session標識,server需要它來驗證的,所以握手時就失敗。而在電腦開發時,websocket連接卻自動帶上了cookie,所以做成了手機與電腦的不一致。
解決辦法,連接時加上session標識
wx.connectSocket({
url: 'wss://example.qq.com',
header:{
'Session-Id': 'xxxxxxxx'
},
success(): function(){
//
}
});
Nginx配置WebSocket反向代理
location /websocket {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
另外,Nginx對外服務可以使用https,RealServer可以只用http
小程序websocket官方說明
基礎庫 1.7.0 之前,一個微信小程序同時只能有一個 WebSocket 連接,如果當前已存在一個 WebSocket 連接,會自動關閉該連接,並重新創建一個 WebSocket 連接。基礎庫版本 1.7.0 及以后,支持存在多個 WebSokcet 連接,每次成功調用 wx.connectSocket 會返回一個新的 SocketTask。— https://mp.weixin.qq.com
示例代碼
wx.connectSocket({
url: 'wss://example.qq.com',
data:{
x: '',
y: ''
},
header:{
'content-type': 'application/json'
},
protocols: ['protocol1'],
method:"GET"
})