以前做小程序為了應急找了個插件去鏈接WebSokcet,文章傳送門。
回過頭在新項目中再次使用時出現了些許問題,不一一贅述。遂決定好好用一下原生的WebSokcet。
一、說明
1.小程序原生的WebSokcet沒有斷線重連機制,這個是他的不足之處。
2.小程序新的版本庫已經支持存在多個 WebSokcet 連接。
官方說明:基礎庫 1.7.0 之前,一個微信小程序同時只能有一個 WebSocket 連接,如果當前已存在一個 WebSocket 連接,會自動關閉該連接,並重新創建一個 WebSocket 連接。基礎庫版本 1.7.0 及以后,支持存在多個 WebSokcet 連接,每次成功調用 wx.connectSocket 會返回一個新的 SocketTask。
官方文檔地址:https://mp.weixin.qq.com/debug/wxadoc/dev/api/network-socket.html#wxclosesocket
二、實際例子:
首先你需要socket地址url: let url = 'wss://xxx.xxx.com/?xxx=xxx'
注意:1.小程序管理后台添加socket域名的時候不能出現端口;2.如果使用了appID,協議必須是 wss;3.socket服務端映射的端口僅支持 80 和 443,和公眾號一個尿性。
接下來放例子:
1、socket.js
const app = getApp(); let url = 'wss://xxx.xxx.com/?xxx=xxx' export const connect = function (cb) { // 定義一個方法 wx.connectSocket({ // 創建一個 WebSocket 連接 url: url, fail (err) { if (err) { console.log('%cWebSocket連接失敗', 'color:red', err) app.globalData.socketConnectFail = true // 定義一個全局變量,當鏈接失敗時改變變量的值 } } }) wx.onSocketOpen(function (res) { // 監聽WebSocket連接打開事件。 console.log('WebSocket打開成功'); wx.sendSocketMessage({ // 通過 WebSocket 連接發送數據,需要先 wx.connectSocket,並在 wx.onSocketOpen 回調之后才能發送。 data: Buffer2Base64(), // 用於訂閱的參數,視具體情況而定 success (data) { console.log('WebSocket發送消息:', data.errMsg) }, fail (err) { console.log('Err', err) } }) }) wx.onSocketMessage(function (res) { // 監聽WebSocket接受到服務器的消息事件。 console.log('WebSocket接收到消息:', ArryBuffer2Json(res.data)); cb(ArryBuffer2Json(res.data)); // 將接收到的消息進行回調,如果是ArryBuffer,需要進行轉換 }) wx.onSocketError(function (res) { // 監聽WebSocket錯誤。 console.log('WebSocket連接打開失敗') }) wx.onSocketClose(function (res) { // 監聽WebSocket關閉。 console.log('WebSocket關閉'); }) };
function ArryBuffer2Json (data) { // ArryBuffer轉換成Json try { var Base64String = String.fromCharCode.apply(null, new Uint8Array(data)); var Base64JsonStr = decodeURIComponent(base64_decode(Base64String)); return JSON.parse(Base64JsonStr); } catch (err) { console.log(err); return false; } } function Buffer2Base64 () { // 用於訂閱的參數,視具體情況而定 var packet = {}; packet["cmd"] = "subscribe"; packet["reqNo"] = "" + new Date().getTime(); packet["params"] = {token: token, channelId: 'xcx', columnIds: "1"}; return stringToBuffer(JSON.stringify(packet)) } function stringToBuffer (string) { var string = base64_encode(encodeURIComponent(string)), charList = string.split(''), uintArray = []; for (var i = 0; i < charList.length; i++) { uintArray.push(charList[i].charCodeAt(0)); } return new Uint8Array(uintArray).buffer; } function base64_encode (str) { // base64編碼 var c1, c2, c3; var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; var i = 0, len = str.length, string = ''; while (i < len) { c1 = str.charCodeAt(i++) & 0xff; if (i == len) { string += base64EncodeChars.charAt(c1 >> 2); string += base64EncodeChars.charAt((c1 & 0x3) << 4); string += "=="; break; } c2 = str.charCodeAt(i++); if (i == len) { string += base64EncodeChars.charAt(c1 >> 2); string += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)); string += base64EncodeChars.charAt((c2 & 0xF) << 2); string += "="; break; } c3 = str.charCodeAt(i++); string += base64EncodeChars.charAt(c1 >> 2); string += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)); string += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6)); string += base64EncodeChars.charAt(c3 & 0x3F) } return string }
function base64_decode (input) { // base64解碼
var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = base64EncodeChars.indexOf(input.charAt(i++));
enc2 = base64EncodeChars.indexOf(input.charAt(i++));
enc3 = base64EncodeChars.indexOf(input.charAt(i++));
enc4 = base64EncodeChars.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
return utf8_decode(output);
}
function utf8_decode (utftext) { // utf-8解碼
var string = '';
let i = 0;
let c = 0;
let c1 = 0;
let c2 = 0;
while (i < utftext.length) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if ((c > 191) && (c < 224)) {
c1 = utftext.charCodeAt(i + 1);
string += String.fromCharCode(((c & 31) << 6) | (c1 & 63));
i += 2;
} else {
c1 = utftext.charCodeAt(i + 1);
c2 = utftext.charCodeAt(i + 2);
string += String.fromCharCode(((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63));
i += 3;
}
}
return string;
}
2、index.js
let openSocket = require('../../config/socket.js'); const app = getApp();
data: { motto: 'Hello World', articleData: [] },
onLoad: function () { let that = this; openSocket.connect(function (data) { // WebSocket初始化連接 let result = data.data if (result) { that.setData({articleData: [result].concat(that.data.articleData)}) // 將獲得的socket推送消息拼接到當前文章列表的最前面 } }); if (app.globalData.socketConnectFail) { // WebSocket斷線重連 setInterval(() => { openSocket.connect(function (data) { let result = data.data if (result) { that.setData({articleData: [result].concat(that.data.articleData)}) } }); }, 1000) } }
3、app.js
globalData: { socketConnectFail: false }