1. 程式人生 > 程式設計 >uniapp,微信小程式中使用 MQTT的問題

uniapp,微信小程式中使用 MQTT的問題

最近在uniapp打包成微信小程式的專案中第一次用到了MQTT。使用比較簡單,但是還是遇到了一些問題。在此記錄一下。

官方文件:MQTT Github

官方MQTT測試工具:MQTTX。測試工具使用說明

MQTT的js檔案:mqtt.min.js

先上一點注意事項:

(1)MQTT.js 一個 MQTT 協議的客戶端庫,用 JavaScript 編寫,可用於 Node.js 和瀏覽器。在 Node.js 端可以通過全域性安裝使用命令列連線,同時還支援 MQTT ,MQTT TLS 證書連線;值得一提的是 MQTT.js 還對微信小程式有較好的支援。

(2)MQTT可以通過三種方式連線,TCP直連,TLS和WebSocket,但是JavaScript使用 TCP 只能通過 ws 即 Websocket 連結。所以如果伺服器是TCP直連,客戶端是肯定連不上的,會報 Error in connection establishment 的錯誤。所以客戶端協議只能是ws,wss,wxs(微信)

(3)WebSocket 是一種在單個 TCP 連線上進行全雙工通訊的協議。作為一種通訊協議,其使用 ws(非加密)、wss(SSL 加密) 作為協議標識。MQTT.js 客戶端支援多種協議,連線地址需指明協議型別;

(4)ws: 未加密的 WebSocket 連線,一般使用8083埠。wss: 加密的 WebSocket 連線,一般使用8084埠。mqtt: 未加密的 TCP 連線,一般使用1883埠。mqtts: 加密 TCP 連線。

貼一下程式碼:

import $mqtt from './mqtt.min.js';

const mqttOptions = {
  keepalive: 30,clean: false,connectTimeout: 5000,// Timeout
  clientId: uni.getStorageSync('clientId'),// username: 'test',// password: 'test',}

const connectUrl = `${mqttHost}:${mqttPort}/mqtt`;

// #ifdef H5
var client = $mqtt.connect('wss://' + connectUrl,mqttOptions);
// #endif

// #ifdef MP-WEIXIN||APP-PLUS
var client = $mqtt.connect('wxs://' + connectUrl,mqttOptions);
// #endif

client.on('connect',() => {
  console.log('connect')
  // 這是為了給自己發條訊息,其它無作用
  client.subscribe('test',(err) => {
    if (!err) {
      client.publish('test','{}')
    }
  })
});
// 自動重連
client.on('reconnect',(msg) => {
  console.log('reconnect',msg)
});
// 錯誤
client.on('error',() => {
  console.log('error')
});
// 斷開
client.on('end',() => {
  console.log('end')
});
// 掉線
client.on('offline',(msg) => {
  console.log('offline',msg)
});
// 收到訊息    
client.on('message',(topic,message) => {
  // 把arrayBuffer轉成字串
  let encodedString = String.fromCharCode.apply(null,new Uint8Array(message));// 全域性傳送訊息
  uni.$emit('sendTopicMsg',encodedString);
   console.log(encodedString)
})

// 全域性監聽是否有關閉mqtt的訊息的事件
uni.$on('closeMqtt',() => {
  client.end(true); // 主動斷開連線
})

說明:

(1) 配置項裡的 keepAlive 指的是心跳時間。以秒為單位。定義服務端從客戶端接收到訊息的最大間隔時間。可以設定為0,表示客戶端一直不斷開,除非主動斷開。

(2) clean 設定為false,是為了讓客戶端掉線的時候,伺服器必須在客戶端斷開之後繼續儲存/保持客戶端的訂閱狀態。即當為true的時候,如果掉線了,服務端會清理連結狀態的資料和內容。當為false的時候,服務端會儲存訊息傳送期間,連結斷開導致傳送失敗的訊息。這樣連上的時候就會自動推送到訂閱的客戶端。

(3) 如果連線需要驗證使用者名稱和密碼,則需要加上username和password欄位。

(4) 微信小程式使用的協議,如果不是加密的,則是 wss,如果是加密的,就是 wxs。web端,一般不加密就是 wx,加密就是wss。

(5) 前端收到的訊息是 arrayBuffer 格式的,需要轉成字串格式,如果帶有中文,可能轉成字串會亂碼。可以使用let decodeString = decodeURIComponent(escape((encodedString))) 來避免中文亂碼。或者是網上通過移位轉成中文的方法來解決。

(6) clientId 是使用Math.random().toString(36).substr(3,自定義長度) 來生成自定義長度的的唯一id。

應該是免費的測試MQTT訊息的連結:o(∩_∩)o

協議 地址 路徑 證書
mqtt broker.hivemq.com 8000
mqtt broker.emqx.io 1883
ws test.mosquitto.org 8080 /mqtt
wss test.mosquitto.org 8081 /mqtt CA signed server

(1) CA signed server 這個直接在MQTTX測試工具裡面 選擇 SSL/TLS 勾選為true時即可選擇。

(2) 測試的時候,先填好內容,然後連結上的時候,再新增一個訂閱,Topic就填一會你需要傳送訊息的Topic,這樣當你模擬伺服器傳送訊息的時候,MQTTX裡面也會收到你剛才傳送的內容,這樣就是連通了。

開發過程中遇到的問題:

(1)如果出現failed: Connection closed before receiving a handshake response這個錯誤。說明 服務端的 mqtt 協議和客戶端的協議不一樣,就比如python用的是基於 tcp 的 mqtt ,js是基於websocket 的 mqtt,都不能達成握手的操作。出現這個的問題應該是:服務端使用了1883這個埠,而客戶端也是用這個埠,就導致這個問題。正確的應該是:客戶端(js)應該使用8083埠(未加密)。

(2) 最初我設定心跳時間是3秒,在微信開發者工具,或者H5端的時候,是沒有問題的。但是在小程式真機除錯裡,當小程式切換到後臺,差不多5s就會自動斷開,然後一直重連,直到切換回小程式,重連成功。而且有時候還會連續斷開和重連。自動斷網這個原因,小程式官網做了說明的:超過5s斷網說明在第二條 網路請求 - 使用限制裡面就說明了,小程式的機制,限制了切換到後臺之後網路的處理。所以把心跳時間改為30s,讓 mqtt 30秒之後再自動重連。但是這樣只是為了讓體驗稍微好一點,不會出現切換出去5s就斷開連結,再切回來一直提示重連的問題。不過可以把心跳時間改為0,表示一直連線不斷開。

總結:

(1)以上對mqtt的瞭解也只是一知半解,還沒弄明白這裡的心跳時間,和 TCP/IP 的心跳機制是不是一樣的。超過心跳時間,能不能讓客戶端不掉線,或者有沒有更好的解決離線的辦法。

(2)而且還有很多特性都沒用到,比如will遺願標誌,專門用來處理客戶端斷開連線的配置項。

(3)由於這個專案都是用的Qos0的訊息,都不知道與Qos1,Qos2的區別是什麼。

到此這篇關於uniapp,微信小程式中使用 MQTT的文章就介紹到這了,更多相關微信小程式MQTT內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!