微信小程序中使用 MQTT 实现实时通信:技术难点与实践指南

📌 一、引言

MQTT(Message Queuing Telemetry Transport)是一种轻量级的机器对机器(M2M)通信协议,专为物联网和低带宽环境设计。其核心特点是采用发布/订阅模式,具有低功耗、高效性和高可靠性等优点,非常适合在资源有限的设备上运行。在微信小程序中集成 MQTT 可以实现实时数据传输等功能。本文将详细介绍如何在微信小程序中使用 MQTT,并分析其中的技术难点及注意事项。

🛠️ 二、实施步骤与关键代码解析
  1. 引入 MQTT 库 :微信小程序本身不直接提供 MQTT 客户端功能,因此需要借助第三方库来实现。目前常用的 mqtt.js 版本有多个,如 v4.1.0 等。开发者可以根据项目需求选择合适的版本,并将其拷贝至项目根目录下新建的 utils 文件夹中,随后通过 import mqtt from "../../utils/mqtt.min.js" 方式引入mqtt.js v4.1.0 下载地址

  2. 建立连接:微信小程序安全要求较高,与后台服务器之间的通讯必须使用 https/wss 协议。但由于部分用于测试的未备案域名无法完成常规配置,所以在微信开发工具中需勾选【不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书】选项。若已有备案过的自有 MQTT 服务器,则按要求完成相应配置即可(登录小程序后台》开发管理》服务器域名》socket合法域名)。以下是典型连接代码示例:

微信小程序中的 app.js

复制代码
// app.js
import mqtt from "./utils/mqtt.min";
let connected = false;
// // 重连次数
// let reconnectAttempts = 0;

App({
async onLaunch() {},
onShow(options) {
 connected = false;
 this.globalData.mqttConnected = false;
},
onHide(options) {
 this.disconnectMQTT();
},
initMqtt(cb) {
 if (connected) {
   cb && cb();
   return;
 }
 // MQTT连接选项
 const options = {
   connectTimeout: 4000,
   clientId: "wxapp_ca_" + Math.random().toString(16).substring(2, 10),
   username: "实际用户名",
   password: "实际用密码",
   clean: true,
   // 配置CA证书验证
   ca: `-----BEGIN CERTIFICATE-----
   MIIE/jCCA+agAwIBAgISBp77eeZKOPZRNgqf+FQ0YuXUMA0GCSqGSIb3DQEBCwUA
   MDMxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQwwCgYDVQQD
   EwNSMTMwHhcNMjUwODIyMDE0ODU3WhcNMjUxMTIwMDE0ODU2WjAcMRowGAYDVQQD
   ExF6aGN3LmJhbmtwZXRzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
   ggEBALzWv64Rm874UDTfvtuO4C0ny4WnmEVWeERzRfNNCJZRN/r9PizycLyJbUfG
   1gUW6sCRT1Pzy72Q4dDt/i6k/bLQAE/0ilisc5Y4TQ3rQ5jGo3HVbk8HPfCHx57f
   muHyQzcwofPyn8Zo+Zgvsg/hx8zTAOW9+tWsfAy+pxcF43aoSEvaxm6RCXYI80IO
   MIIE/jCCA+agAwIBAgISBp77eeZKOPZRNgqf+FQ0YuXUMA0GCSqGSIb3DQEBCwUA
   MDMxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQwwCgYDVQQD
   EwNSMTMwHhcNMjUwODIyMDE0ODU3WhcNMjUxMTIwMDE0ODU2WjAcMRowGAYDVQQD
   ExF6aGN3LmJhbmtwZXRzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
   ggEBALzWv64Rm874UDTfvtuO4C0ny4WnmEVWeERzRfNNCJZRN/r9PizycLyJbUfG
   1gUW6sCRT1Pzy72Q4dDt/i6k/bLQAE/0ilisc5Y4TQ3rQ5jGo3HVbk8HPfCHx57f
   muHyQzcwofPyn8Zo+Zgvsg/hx8zTAOW9+tWsfAy+pxcF43aoSEvaxm6RCXYI80IO
   r4b80pgPzoKTKFOewYzNVITS65kNdOjK
   -----END CERTIFICATE-----`,
   // 强制验证服务器证书,不需要证书可设为false,不传ca
   rejectUnauthorized: true,
   // 额外的TLS选项(可选)
   secureProtocol: "",
 };

 // 连接地址(MQTT服务器WSS地址)
 const connectUrl = "wxs://example.com:8083/mqtt";
 // 建立连接
 this.globalData.client = mqtt.connect(connectUrl, options);
 // 监听连接成功
 this.globalData.client.on("connect", () => {
   console.log("MQTT 连接成功(已验证CA证书)");
   connected = true;
   this.globalData.mqttConnected = true;
   cb && cb();
   // 订阅主题
   // this.subscribeTopic()
 });

 // // 监听接收消息
 // this.globalData.client.on('message', (topic, message) => {
 //   const newMessage = {
 //     time: new Date().toLocaleString(),
 //     topic: topic,
 //     content: message.toString() && utils.jsonStrToJson(message.toString()),
 //   }
 //   console.log(1111, newMessage);
 //   this.globalData.messages = newMessage
 // })

 this.globalData.client.on("error", (err) => {
   console.error("MQTT 错误:", err);
   let errorMsg = "连接失败";
   if (err.message.includes("certificate")) {
     errorMsg = "证书验证失败";
   } else if (err.message.includes("connection refused")) {
     errorMsg = "连接被拒绝(检查账号密码)";
   }
   wx.showToast({
     title: errorMsg,
     icon: "none",
     duration: 3000,
   });
   this.disconnectMQTT();
 });

 this.globalData.client.on("reconnect", () => {
   // if (reconnectAttempts >= 5) {
   //   // 重连5次
   try {
     this.globalData.client.end();
     connected = false;
     this.globalData.mqttConnected = false;
     console.log("重连失败");
     this.initMqtt(cb);
   } catch (error) {}
   //   return;
   // }
   // reconnectAttempts++;
   console.log("正在重连...");
   // wx.showToast({
   //   title: "正在重连...",
   //   icon: "loading",
   //   duration: 2000,
   // });
 });

 this.globalData.client.on("close", () => {
   console.log("连接已断开close");
   connected = false;
   this.globalData.mqttConnected = false;
 });
},
// 订阅主题
subscribeTopic(topic, option = { qos: 0 }) {
 try {
   if (!connected) return;
   this.globalData.client.subscribe(topic, option, (err) => {
     if (!err) {
       console.log("已订阅主题: ", topic);
     } else {
       console.error("订阅失败:", err);
       // wx.showToast({
       //   title: "订阅失败: " + topic,
       //   icon: "none",
       //   duration: 2000,
       // });
     }
   });
 } catch (error) {}
},
// 取消订阅主题
unsubscribeTopic(topic) {
 try {
   if (!connected) return;
   this.globalData.client.unsubscribe(topic, (err) => {
     if (!err) {
       console.log("取消订阅主题: ", topic);
     } else {
       console.error("取消订阅失败:", err);
       wx.showToast({
         title: "取消订阅失败: ",
         topic,
         icon: "none",
         duration: 2000,
       });
     }
   });
 } catch (error) {}
},
// 发布消息
publishTopic(topic, message) {
 try {
   if (!connected) return;
   this.globalData.client.publish(topic, message, { qos: 0 }, (err) => {
     if (!err) {
       console.log("发布消息成功: ", topic, message);
     } else {
       console.error("发布消息失败:", err);
       wx.showToast({
         title: "发布消息失败: " + topic,
         icon: "none",
         duration: 2000,
       });
     }
   });
 } catch (error) {}
},
// 断开连接
disconnectMQTT() {
 try {
   if (this.globalData.client && connected) {
     this.globalData.client.end();
     connected = false;
     this.globalData.mqttConnected = false;
     console.log("已断开连接end");
   }
 } catch (error) {}
},
globalData: {},
});
  • clientId :需要提供一个唯一的clientId
  • username: 实际用户名
  • password:实际用密码
  • ca:配置CA证书验证
  • rejectUnauthorized : 强制验证服务器证书,不需要证书可设为false,不传ca
  • connectUrl : "wxs://example.com:8083/mqtt",微信需要使用wxs安全协议,小程序后台》开发管理》服务器域名》socket合法域名配置的是wss://example.com
  • 断开连接:当不再需要与 MQTT 服务器保持连接时,可调用相应方法断开连接,以释放资源
  • 订阅主题:允许小程序订阅特定的主题,从而接收来自该主题的消息
  • 取消订阅:当不需要接收某个主题的消息时,可进行取消订阅操作
  • 发布消息:小程序可以向指定的主题发布消息,与其他设备或服务进行通信

使用,我是在页面中的onShow方法中调用MQTT,然后订阅主题。

javascript 复制代码
let app = getApp();
Page({
	onShow() {
	  this.initMqttFun();
	},
	initMqttFun() {
	  app.initMqtt(() => {
	    if (app.globalData.mqttConnected) {
	      let topic1 = `订阅主题`;
	      let topic2 = `订阅主题`;
	      app.subscribeTopic(topic1);
	      app.subscribeTopic(topic2, { qos: 1 });
	      app.globalData.client.on("message", (topic, message) => {
	        console.log(topic, message.toString());
	      });
	    }
	  });
	},
});
🌟 三、技术难点剖析
  1. 协议适配问题 :微信小程序对网络通信有严格规范,普通的 WebSocket 协议在此场景下受限,必须使用特殊的 "wxs" 协议来替代标准的 WSS 协议进行 MQTT 连接。这一改动增加了开发的复杂性,容易因协议书写错误导致连接失败。

  2. ClientID 管理 :如果连接使用的 clientId 重复,会出现互相顶掉线的情况。这意味着开发者需要在生成 clientId 时确保唯一性,通常会结合时间戳等因素动态生成,避免冲突影响正常连接和使用。

  3. 消息质量服务水平的选择与保障MQTT 提供了三种消息传递保证级别(QoS 0、1、2),不同的级别适用于不同的业务场景。在选择合适 QoS 级别的同时,还要确保在整个通信过程中能够正确处理各种异常情况,以保证消息的准确性和完整性。例如在一些关键数据的传输场景下,可能需要更高的 QoS 级别来保证数据不丢失且仅被处理一次。

  4. 跨平台兼容性挑战 :尽管这里主要讨论的是微信小程序环境,但在实际应用中可能会涉及到与其他平台或设备的交互。不同平台的 MQTT 实现可能存在差异,这就需要进行充分的测试和调试,以确保跨平台的兼容性良好。特别是在一些复杂的物联网架构中,多种类型的设备都可能参与到基于 MQTT 的通信体系中,协调好各方的差异至关重要。

⚠️ 四、注意事项汇总
  1. 域名备案与配置 :如果有自己的 MQTT 服务器并且进行了 ICP 备案,那么可以直接按照正规流程在微信公众平台进行配置,无需勾选那些绕过校验的选项。但如果使用的是未备案的测试服务器,就必须按照前述方法勾选相关选项,否则无法建立连接,证书必须有正规CA机构签发(如:阿里云SSL等),自签名证书会被小程序决绝,我就是使用了自签名证书,导致在开发工具中正常使用,手机端不能使用,一直重新链接,查看mqtt.js源码,发现它也是使用wx.connectSocket实现的,我在里面添加了wx.onSocketError才监听到错误errCode: 1004 errMsg: "open fail: _code:8,_msg:TLS handshake failed",想了各种办法后来才发现是证书的问题。微信小程序无法使用1883端口的明文MQTT链接,必须通过加密协议(mqtts://wss://)及合规端口(4438883等)实现。

  2. 错误处理机制完善 :在整个 MQTT 连接和使用过程中,不可避免地会遇到各种错误情况,如网络波动导致的连接中断、认证失败等。开发者应当建立健全的错误处理机制,及时捕获并处理这些错误,为用户提供友好提示的同时尽量恢复连接或采取补救措施。

  3. 性能优化考量 :由于微信小程序运行环境和资源有限,在使用 MQTT 时要关注性能优化。合理设置重连间隔时间、控制消息频率和大小等参数,避免频繁的网络请求和过多的数据处理导致小程序卡顿甚至崩溃。

  4. 安全性重视 :除了遵循微信小程序的安全规范外,还应考虑 MQTT 自身的安全机制。例如可以根据实际需求启用用户名密码认证等功能,防止非法设备接入和数据泄露风险。尤其是在涉及敏感信息的传输场景下,加密传输等方式也应纳入考虑范围。

🔄 五、推荐使用版本介绍

对于原生微信小程序而言,推荐使用 MQTT.js v4.2.1v4.2.0v4.1.0v2.18.8 这几个版本。而对于使用 uniapp 框架搭建的微信小程序项目,则可选择 v4.1.0v2.18.8。如果在调试过程中遇到真机调试有问题但模拟器正常的情况,可以尝试切换不同的 mqtt.js 版本来解决。

相关推荐
前端小万1 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
MoonMoonLee1 天前
小程序配置
小程序
拖孩2 天前
代码我能全交给 AI,流量主这 500 个访客它一个都替不了我
前端·后端·微信小程序
2501_916007472 天前
苹果商店iOS应用上架费用全面解析:开发者计划与审核费用计算
android·ios·小程序·https·uni-app·iphone·webview
JQweryuiop2 天前
中小型游戏陪练工作室数字化管理实践:基于七彩屋电竞护航小程序订单、履约与绩效系统的落地复盘
大数据·游戏·小程序·架构
Ai-_Man2 天前
您您这可以把Mistral AI的多个会话比如说。左侧的多个会话一次性导出吗?不是单条会话里面的多次会对话。
人工智能·ai·小程序·电脑
2501_916008892 天前
如何实现iOS App代码混淆:SwiftShield使用指南
android·ios·小程序·https·uni-app·iphone·webview
微擎应用市场2 天前
简单拼车小程序系统:实现出行与物流资源的高效精准匹配
小程序
SL-staff2 天前
MQTT Topic权限越界排查指南:JVS-IOT中系统Topic与自定义Topic的鉴权机制与实操验证
mqtt·嵌入式开发·权限控制·物联网开发·协议分析·鉴权机制·jvs-iot
甜到心里的蛋糕2 天前
如何用企业微信实现让微信收到通知实时通知
服务器·python·微信小程序·fastapi