vue 项目如何使用 mqtt 通信

一、 什么是 MQTT?

MQTT(Message Queuing Telemetry Transport)是一种轻量级、基于发布-订阅模式的消息传输协议,适用于资源受限的设备和低带宽、高延迟或不稳定的网络环境。它在物联网应用中广受欢迎,能够实现传感器、执行器和其它设备之间的高效通信。

二、MQTT 的工作原理

MQTT 是基于发布-订阅模式的通信协议,由 MQTT 客户端通过主题(Topic)发布或订阅消息,通过 MQTT Broker 集中管理消息路由,并依据预设的服务质量等级(QoS)确保端到端消息传递可靠性。

QoS

MQTT 提供了三种服务质量(QoS),在不同网络环境下保证消息的可靠性。

  • QoS 0:消息最多传送一次。如果当前客户端不可用,它将丢失这条消息。
  • QoS 1:消息至少传送一次。
  • QoS 2:消息只传送一次。

关于 MQTT QoS 的更多详情,请参阅文章 MQTT QoS 0, 1, 2 介绍

三、MQTT 的工作流程

在了解了 MQTT 的基本组件之后,让我们来看看它的一般工作流程:

  1. 客户端使用 TCP/IP 协议与 Broker 建立连接,可以选择使用 TLS/SSL 加密来实现安全通信。客户端提供认证信息,并指定会话类型(Clean Session 或 Persistent Session)。
  2. 客户端既可以向特定主题发布消息,也可以订阅主题以接收消息。当客户端发布消息时,它会将消息发送给 MQTT Broker;而当客户端订阅消息时,它会接收与订阅主题相关的消息。
  3. MQTT Broker 接收发布的消息,并将这些消息转发给订阅了对应主题的客户端。它根据 QoS 等级确保消息可靠传递,并根据会话类型为断开连接的客户端存储消息。

四、MQTT 基础和配置

1.安装和引入 MQTT 客户端库

使用 NPM 或 Yarn 来安装 mqtt.js 是一个直接且高效的方式,这将允许你将MQTT集成到你的Vue项目中。安装方式如下:

js 复制代码
npm install mqtt --save
or
yarn add mqtt

在 Vue 项目中使用 MQTT 首先要进行客户端库的安装:

js 复制代码
import mqtt from 'mqtt'

2.配置 MQTT 连接

连接前需要配置好MQTT服务器的地址和端口:

js 复制代码
const options = {
  host: '你的MQTT服务器地址',
  port: 你的MQTT服务器端口,
  username: 'admin', // 实际环境中应使用JWT令牌
  password: 'public',
  clean: false, // true默认值/false 保持会话,重连后可接收离线消息
  connectTimeout: 40000, // 超时时间设置
  clientId: 'emqx_vue2_' + Math.random().toString(16).substring(2, 8), // 客户端ID
   // 60秒心跳,表示客户端将每隔60秒发送一次心跳包(PINGREQ)到服务器,服务器会响应
  keepalive: 60, 
  // 其他配置...
};

3.连接服务器和会话管理

连接 MQTT 服务器

创建 MQTT 客户端实例并进行连接:

js 复制代码
const client = mqtt.connect(options);

管理 MQTT 会话

你可以通过监听不同的事件来管理会话,例如:

js 复制代码
client.on('connect', () => {
  console.log('连接成功');
});
js 复制代码
client.on('error', (err) => {
  console.error('连接失败:', err);
});

4.主题订阅与发布消息

订阅主题

订阅 MQTT 主题,以便接收相关消息:

js 复制代码
client.subscribe('你的主题', { qos: 1 }, (err) => {
  if (err) {
    console.error('订阅失败:', err);
  } else {
    console.log('订阅成功');
  }
});

5.发布消息

向特定主题发布消息:

js 复制代码
client.publish('你的主题', '要发送的消息内容', { qos: 1, retAIn: false }, (err) => {
  if (err) {
    console.error('发布消息失败:', err);
  }
});

6.处理收到的消息

设置消息监听器

接收并处理来自订阅主题的消息:

js 复制代码
// 接收消息处理
client.on('message', (topic, message) => {
  console.log(`收到消息:${message.toString()}`);
});

7.断开连接

js 复制代码
 client.on('unsubscribe', error => {
    console.log('断开连接:', error)
 })

8.安全性和性能优化

实现 TLS 加密连接

确保通信的安全性,可以使用 TLS 对链接进行加密处理:

js 复制代码
const options = {
  //...其他配置
  connectTimeout: 4000, // 超时时间设置

  // 使用 TLS
  ca: fs.readFileSync('path/to/ca.crt'),
  key: fs.readFileSync('path/to/client.key'),
  cert: fs.readFileSync('path/to/client.crt'),
  rejectUnauthorized: false
};

QoS 和持久会话

设置 QoS 等级以及是否开启持久会话,以满足不同的业务需求:

js 复制代码
const options = {
  ...其他配置,
  clean: true, // 设置为false开启持久会话
  qos: 1  // 消息至少传送一次
};

注:

  • clean: true 干净会话 | 每次连接都创建新的会话,不保留任何状态;
  • clean: false 持久会话保留会话状态,包括订阅和未送达的消息;

9.断线重连和异常处理

处理断线重连

监听 close 事件,并制定重连策略:

js 复制代码
client.on('close', () => {
  console.log('连接关闭,尝试重连');
  // 实现重连逻辑...
});

异常处理建议

编写合适的异常处理逻辑来保障系统稳定运行

js 复制代码
// 可以结合 try...catch 使用
try {
  // MQTT 相关操作
} catch (error) {
  console.error('异常信息:', error);
}

通过以上步骤,Vue 项目中就可以有效集成并使用 MQTT 通信技术了。根据不同项目的特点和需求,这些步骤可能会有所调整和优化。

五、相关问答

1. Vue项目如何使用MQTT进行通信?

MQTT(Message Queuing Telemetry Transport)是一种轻量级的、可靠的、基于发布/订阅模式的消息传输协议。在Vue项目中,您可以使用MQTT实现实时的消息传递和通信。

首先,您需要确保您的Vue项目中已经安装了MQTT客户端库。您可以使用npm或yarn来安装依赖项。例如,您可以运行以下命令来安装一个常用的MQTT库:

js 复制代码
npm install mqtt --save

接下来,在您的Vue组件中引入MQTT库并创建一个MQTT客户端实例。您需要指定MQTT服务器的主机名和端口号,并且可以选择配置其他参数,如用户名、密码等。例如:

js 复制代码
import mqtt from 'mqtt'

const client = mqtt.connect('mqtt://mqtt.server.com:1883', {
  username: 'your_username',
  password: 'your_password'
})

一旦建立了MQTT客户端连接,您可以使用MQTT提供的API发送和接收消息。您可以使用publish()方法发送消息,使用subscribe()方法订阅主题,并使用on()方法监听收到的消息。例如:

js 复制代码
// 发送消息
client.publish('topic', 'Hello, MQTT!')

// 订阅主题,并监听收到的消息
client.subscribe('topic')
client.on('message', function (topic, message) {
  console.log('Received message:', message.toString())
})

通过使用这些API,您可以在Vue项目中使用MQTT进行实时通信,实现实时消息传递的功能。

2. 如何在Vue项目中配置MQTT的TLS安全连接?

如果您的MQTT服务器要求使用TLS(Transport Layer Security)安全连接,您可以在Vue项目中进行相应的配置来实现安全的MQTT通信。

首先,您需要获得MQTT服务器的TLS证书文件,通常是一个.pem文件。将该证书文件保存到您的Vue项目中的某个目录下,例如public目录

接下来,在您的Vue组件中引入MQTT库,并使用tls选项指定TLS相关配置。例如:

js 复制代码
import mqtt from 'mqtt'
import fs from 'fs'

const options = {
  host: 'mqtt.server.com',
  port: 8883,
  key: fs.readFileSync('public/client.key'),
  cert: fs.readFileSync('public/client.crt'),
  ca: fs.readFileSync('public/ca.crt')
}

const client = mqtt.connect(options)

在上面的示例中,keycertca选项分别指定了客户端的私钥、证书和服务器的CA证书。您需要将这些选项的值替换为相应的文件路径。

通过使用上述配置,您的Vue项目将能够通过TLS安全连接与MQTT服务器进行通信。

3. 如何实现Vue项目中的双向MQTT通信?

双向MQTT通信在Vue项目中非常有用,它允许您实时地发送和接收来自MQTT服务器的消息。

首先,您需要创建两个独立的MQTT客户端实例,一个用于发送消息,一个用于接收消息。例如:

js 复制代码
import mqtt from 'mqtt'
const sendClient = mqtt.connect('mqtt://mqtt.server.com:1883')
const receiveClient = mqtt.connect('mqtt://mqtt.server.com:1883')

接下来,您可以使用sendClient发送消息,使用receiveClient接收消息。例如:

js 复制代码
// 发送消息
sendClient.publish('topic', 'Hello, MQTT!')

// 接收消息
receiveClient.subscribe('topic')
receiveClient.on('message', function (topic, message) {
  console.log('Received message:', message.toString())
})

通过使用两个独立的客户端实例,您可以在Vue项目中实现双向的MQTT通信,实时地发送和接收消息。这样,您就可以构建类似实时聊天、实时数据更新等功能。

4.client.on('close')client.on('unsubscribe') 的区别详解

这两个事件监听的是MQTT客户端生命周期中完全不同阶段的行为,让我详细解释它们的区别:

事件对比总览

事件 触发时机 用途 参数 频率
close 连接完全关闭时 连接生命周期管理 每个连接1次
unsubscribe 成功取消订阅主题时 订阅管理 取消的主题数组 可多次触发

详细解析

  1. client.on('close') - 连接关闭事件

触发时机:当MQTT客户端与服务器的连接完全关闭时触发。

js 复制代码
client.on('close', () => {
  console.log('🔌 MQTT连接已完全关闭');
  // 执行清理操作
});

典型场景

js 复制代码
const client = mqtt.connect('ws://broker.emqx.io:8083/mqtt');

// 手动关闭连接
client.end(false, () => {
  // 这里的回调执行后会触发 'close' 事件
});

// 监听关闭事件
client.on('close', () => {
  console.log('连接已关闭,可以进行资源清理');
  updateUIStatus('disconnected');
});

// 其他可能触发close的情况:
// - 网络断开
// - 服务器主动关闭连接
// - 客户端调用 client.end()
  1. client.on('unsubscribe') - 取消订阅事件

触发时机:当客户端成功从主题取消订阅时触发。

js 复制代码
client.on('unsubscribe', (unsubscribedTopics) => {
  console.log('✅ 成功取消订阅:', unsubscribedTopics);
  // unsubscribedTopics 是一个数组,包含取消的主题列表
});

典型场景

js 复制代码
// 订阅多个主题
client.subscribe(['topic/sensors', 'topic/status', 'topic/alerts'], { qos: 1 });

// 后来取消部分订阅
client.unsubscribe(['topic/alerts', 'topic/status'], (err) => {
  if (!err) {
    console.log('取消订阅命令已发送');
  }
});

// 监听取消订阅成功事件
client.on('unsubscribe', (topics) => {
  console.log(`已取消订阅: ${topics.join(', ')}`);
  // 更新UI,移除对应的主题显示
  topics.forEach(topic => removeTopicFromUI(topic));
});

总结

关键区别

  • close:连接级别的生命周期事件,表示整个MQTT连接的终止
  • unsubscribe:订阅级别的操作事件,表示从特定主题取消订阅

使用建议

  • close 事件处理连接断开后的全局清理工作
  • unsubscribe 事件管理订阅状态和更新UI
  • 记住事件触发的顺序:取消订阅操作 → unsubscribe 事件 → 断开连接 → close 事件

六、项目实例

首先在项目中新建src/Utils/sysconstant.js文件用来配置常用信息

js 复制代码
// 正式环境  
export const MQTT_SERVICE = window.tsl_global_config.mqttService.url  
export const MQTT_USERNAME = window.tsl_global_config.mqttService.username  
export const MQTT_PASSWORD = window.tsl_global_config.mqttService.password

在vue2组件使用MQTT通信

js 复制代码
import { connect as mqttConnect } from 'mqtt'
import { MQTT_SERVICE, MQTT_USERNAME, MQTT_PASSWORD } from '@/Utils/sysconstant.js'

let client = null

// 初始化MQTT连接
const options = {
  connectTimeout: 40000,
  clientId: 'emqx_vue3_' + Math.random().toString(16).substring(2, 8),
  keepalive: 60, // 60秒心跳
  username: MQTT_USERNAME,
  password: MQTT_PASSWORD,
  clean: false, // 保持会话,重连后可接收离线消息
}

// 连接到broker
client = mqttConnect.connect(MQTT_SERVICE, options)

mounted() {
  this.getMqttMsg()
},
methods: {
    getMqttMsg() {
      // 连接成功
      client.on('connect', () => {
        // console.log('连接成功:', e)
        // 弹窗提示
        ElNotification(
            { 
                title: '连接成功', 
                message: '已成功连接到消息服务器', 
                type: 'success', 
                duration: 3000 
            }
        )

        // 订阅用户专属主题
        const topics = [ `user/${this.userId}/notifications`, `user/${this.userId}/recall` ]
        
        client.subscribe(topics, { qos: 1 }, (err) => {
            if (!err) {
              console.log(`已订阅主题: ${topics.join(', ')}`)
            } else {
              console.error('订阅主题失败:', err)
              Notification.error({
                title: '订阅失败',
                message: '无法订阅通知主题'
              })
            }
        })
        
        // 或者分开订阅用户专属主题
        client.subscribe('user/${this.userId}/notifications',{ qos: 1 },error => {
          if (!error) {
            // console.log('订阅成功1')
          } else {
            console.log('订阅失败1')
            ElNotification(
               { 
                    title: '订阅失败', 
                    message: '无法订阅通知主题', 
                    type: 'error' 
               }
            )
          }
        })

        client.subscribe('`user/${this.userId}/recall',{ qos: 1 }, error => {
          if (!error) {
            // console.log('订阅成功2')
          } else {
            console.log('订阅失败2')
          }
        })
      })

      // 接收消息处理
      client.on('message', (topic, message) => {
        // console.log('收到来自', topic, '的消息', message.toString())

        // 处理接收的消息
        if (topic === '/captureLog/platform/car') {
          let carMqttObj = JSON.parse(message.toString())
          carMqttObj.captureTime = formatDate(carMqttObj.captureTime, 'HH:mm')
          this.carRecords.unshift(carMqttObj)
          console.log(this.carRecords, 'this.carRecords')
        } else {
          let peopleMqttObj = JSON.parse(message.toString())
          peopleMqttObj.openTime = formatDate(peopleMqttObj.openTime, 'HH:mm')
          this.manRecords.unshift(peopleMqttObj)
        }
      })
    }
    
    // 连接断开
    client.on('close', () => {
      console.log('MQTT连接已关闭')
      // this.connected = false
      // this.scheduleReconnect()
    })
    
   // 连接错误
   client.on('error', (err) => {
      this.connected = false
      console.error('MQTT错误:', err)
      
      Notification.error({
        title: '连接错误',
        message: '消息服务连接发生错误'
      })
      
      this.scheduleReconnect()
    })

   // 重连中
   client.on('reconnect', () => {
     console.log('正在重连到MQTT服务器...')
   })
},
相关推荐
前端老宋Running4 小时前
一次从“卡顿地狱”到“丝般顺滑”的 React 搜索优化实战
前端·react.js·掘金日报
隔壁的大叔4 小时前
如何自己构建一个Markdown增量渲染器
前端·javascript
用户4445543654264 小时前
Android的自定义View
前端
WILLF4 小时前
HTML iframe 标签
前端·javascript
枫,为落叶5 小时前
Axios使用教程(一)
前端
小章鱼学前端5 小时前
2025 年最新 Fabric.js 实战:一个完整可上线的图片选区标注组件(含全部源码).
前端·vue.js
ohyeah5 小时前
JavaScript 词法作用域、作用域链与闭包:从代码看机制
前端·javascript
流星稍逝5 小时前
手搓一个简简单单进度条
前端
涔溪5 小时前
实现将 Vue3 项目作为子应用,通过无界(Wujie)微前端框架接入到 Vue2 主应用中(Vue2 为主应用,Vue3 为子应用)
vue.js·前端框架·wujie
倚栏听风雨5 小时前
详解 TypeScript 中,async 和 await
前端