一想到你我就呕…呕呕~~~,咳咳,跑偏了。这篇文章主要记录我在vue使用mqtt的过程,以便大家少走弯路
MQTT为何物?(各位看官,马上会有一堆废话,注意走位)
百度百科:
MQTT是一个基于客户端-服务器的消息发布/订阅传输协议。MQTT协议是轻量、简单、开放和易于实现的,基于TCP/IP;
有三种消息发布服务质量(qos):
“至多一次”,消息发布完全依赖底层 TCP/IP 网络。会发生消息丢失或重复。这一级别可用于如下情况,环境传感器数据,丢失一次读记录无所谓,因为不久后还会有第二次发送。
“至少一次”,确保消息到达,但消息重复可能会发生。
“只有一次”,确保消息到达一次。这一级别可用于如下情况,在计费系统中,消息重复或丢失会导致不正确的结果。
我的理解:如果A与B要通信,其中需要一个消息中间件C(broker),无论A/B谁发布消息(理想情况是有更新时就发布),都发向C,无论谁订阅消息都向C订阅,然后不断获取到最新的A/B的消息。订阅的终端可有多个(类似,北斗只负责发位置信息,终端设备只需要获取就可以了,且是最新的)。
大概这样子(嘘…菜鸟教程上偷的图):
正文
cnpm install mqtt -S//这样默认给你安装的是4.1.0版本
总共主流版本有三个(我是jsdelivr看的, 【写文章时最新时4.1.0】其实@4.1.0是默认安装,所以它的高下载量并不代表其稳定,就像现在的4.2.6一样)
建议大家安装3.0.0或2.18.8,
2021年5月19日13:32:13更新
版本@3.0.0 、@4.2.6,当连续(for循环)发布2个以上链接时,连接成功,当时除第一个外都会发布失败(client disconnecting),我已经降版本到2.18.8!哎~~
cnpm install mqtt@3.0.0 -S
因为ie(包括以ie为内核的360急速浏览器)上不识别4.1.0版本的es6语法。我曾尝试在babel.config.js有过如下配置想转为es5.
module.exports = { presets: [ ['@vue/app', { 'polyfills': [ 'es6.promise', 'es6.symbol' ], useBuiltIns: 'usage' //使用usage不用安装babel/polyfill和引入 }] ], plugins: ['@babel/plugin-transform-arrow-functions']//需要安装 }
import mqtt from "mqtt"
//引入connect配置import { mqttConfig } from "../../commonParams/index.js"
端口,用户名,密码是后台约定(提供)
下面我注释掉的配置项是默认配置,什么?你不信?看这MQTT.js#connect
//commonParams/index.js export const mqttConfig = { port: 8083, // keepalive: 60, // clientId: 'mqttjs_' + Math.random().toString(16).substr(2, 8), // protocolId: 'MQTT', // protocolVersion: 4, // clean: true, }
定义了两个函数:
/* 注释中所提到的后台即为发布端/订阅端, */ // 初始化mqtt initMqtt(topic){ const _this = this; //建立连接,需要搭建消息中间件服务器的(我这里是后台)提供用户名或密码 const cfg = Object.assign(mqttConfig, { username: 'xxxx1', password: 'xxx2', }); // 在data中定义MQTT,以便断开连接 // ws://xxxxx是连接地址,后台提供,wss是https连接 _this.MQTT = mqtt.connect('ws://xxxxx', cfg) _this.MQTT.on('error', (e) => { _this.MQTT.end(); }); //建立连接后订阅主题 _this.MQTT.on('connect', () => { // 订阅一个主题 _this.MQTT.subscribe(topic, { qos: 1 }, err => { if (!err) { console.info(' ---- 订阅成功') }else{ console.warn('订阅失败') } }) }); // 后台发送的消息 _this.MQTT.on('message', function (top, message) { //发送过来的如果是对象你是需要解析的。 const res = JSON.parse(message.toString()); const TOP = top.replace('tops/',''); console.log(top + ': ', res); //根据不同主题进行赋值操作 switch(TOP){ case "top1": _this.data1 = [res]; break; case "top2": _this.data2 = [...res]; break; //其他情况 } }); // 其他异常事件 _this.MQTT.on('reconnect', () => { console.info('正在重连') }); _this.MQTT.on('disconnect', (error) => { console.info('服务器断开:', error) }); _this.MQTT.on('close', () => { _this.MQTT.end(); }); },
上面你可能注意到,this.MQTT为全局变量,这是为了离开此页面时销毁mqtt链接
beforeDestroy(){ if(this.MQTT.end) this.MQTT.end();},
// 发布mqtt,用户名密码和连接配置找后台要 mqttPublish(topic){ const _this = this; const cfg = Object.assign(mqttConfig, { username: 'xxx2', password: 'xxxx', }); _this.MQTT = mqtt.connect('ws://xxxx', cfg) _this.MQTT.on('connect', (e) => { //建立连接后就发布就行了,主题和后台约定。 //还有qos,就是开头提到的消息发布服务质量。 _this.MQTT.publish(topic,JSON.stringify(_this.publicMSG), { qos: 1 }, error => { if (!error) { this.MQTT.end(); }else{ console.warn('发布失败') } }) }); },
created(){ /* + 通配一层(tops/x,top/x1), # 通配0~多层(tops/x, tops/,tops/x/x/x) 当有多个主题是,前面分个一级主题(tops)比较适合后面跟+号就所有 tops/ 开头都能订阅了 */ this.initMqtt('tops/+'); },
需要发布时:
//注意后台订阅的时候一级主题也是tops,你们约定就行 this.mqttPublish('tops/top3')
以上。
予人玫瑰,手留余香~~~,