前端对接MQTT数据库

521 阅读5分钟

背景

公司是做数字孪生可视化的,有一个以B/S架构为基础,围绕数字孪生全要素场景,帮助用户轻松快速构建专业级数字孪生应用的专用产品。

需求

客户有MQTT数据库,需要在我们产品上面对接指标数据,由于前端通常无法直接对接MQTT数据库,因为MQTT是一种基于发布/订阅模式的轻量级通信协议,主要用于物联网设备间的通信,需要在后端实现MQTT协议的客户端,然后通过后端服务器提供的API或WebSocket等方式向前端传输数据。

实现

本次使用Node.js作为后端来读取MQTT的数据,然后将其转换成API接口的形式返回给前端。

前期准备

前期准备包括以下两个步骤:

  1. 创建一个Node.js服务。
  2. 与客户确认MQTT数据中台的地址、端口号、用户名、密码和订阅话题等信息。

搭建Node服务

  1. 安装Node.js,可以从官网下载安装包并按照提示安装。
  2. 在本地创建一个项目文件夹,并在终端中进入该文件夹。
  3. 运行 npm init 命令来初始化项目,并生成 package.json 文件。
  4. 安装 express 框架:npm install express --save
  5. 创建一个名为 app.js 的文件,并在其中编写代码。
const express = require('express');
const app = express();
app.get('/', (req, res) => { res.send('Hello World!'); });
app.listen(3000, () => { console.log('Server is running on port 3000.'); });

上述代码中,我们使用了 express 框架,创建了一个简单的路由 /,并在监听端口 3000。运行 node app.js 启动服务后,访问 http://localhost:3000/ 就可以看到 "Hello World!" 字样。

  1. 在终端中运行 node app.js 命令启动服务。

连接MQTT数据库

  1. 在node根目录创建一个subscribe.js文件
  2. 插入以下代码
const mqtt = require("mqtt");
const fs = require('fs');
const options = {
  username: "aiwater@WT",
  password: "Tenlink@123"
};
// 创建MQTT客户端并连接MQTT代理服务器
const client = mqtt.connect("mqtt:/example.com:1883", options);

// 监听MQTT客户端连接成功事件
client.on("connect", () => {
  console.log("Connected to MQTT broker.");
  // 订阅MQTT主题并在订阅完成后执行回调函数
  client.subscribe("aiwater/mendix/p", (err) => {
    if (err) {
      console.error("Failed to subscribe to topic:", err);
    } else {
      console.log("Subscribed to topic successfully.");
    }
  });
});
// 监听MQTT客户端接收到消息事件
// MQTT协议的消息内容是一个Buffer对象,而不是字符串。Buffer对象是Node.js中表示二进制数据的标准方法。因此,如果需要读取MQTT消息内容,则需要使用toString()将Buffer对象转换为字符串。
client.on("message", (topic, message) => {
  const DATA_PATH = 'D://temp/my.json'; // 数据文件位置 会在该目录创建该json文件
  let mqttData = message.toString(); //接收mqtt数据
  let b = fs.existsSync(DATA_PATH);
  // 检查是否存在指定的JSON文件。如果存在,则使用fs.writeFileSync()方法向该文件写入消息内容;如果不存在,则创建该文件并向其中写入消息内容。
  if (b) {
    fs.writeFileSync(DATA_PATH, mqttData);
  } else {
    let fd = fs.openSync(DATA_PATH, 'w');
    fs.writeFileSync(fd, mqttData);
  }
});

client.on("error", (err) => {
  console.error("An error occurred:", err);
});

  1. 最后,在终端中运行 node subscribe.js 启动服务。就可以在根目录看到my.json文件并且已经把数据写入了。
  2. 至此,mqtt数据读取并保存到本地已结束。

转换成API接口

  1. 在搭建node服务时已经安装了Express框架,这里使用Express创建路由。
  2. 创建路由文件并编写路由处理函数。例如,在 /routes/readMqtt.js 文件中,定义了一个 /readMqtt 路由,并在其中编写了 GET 请求的处理函数:(没有routes文件夹需在根目录手动创建)。并插入以下代码。
var express = require('express');
var router = express.Router();
const fs = require('fs');
const DATA_PATH = 'D://temp/my.json'; //此处应和连接MQTT数据库时创建的路径一致
router.get('/', function(req, res, next) {
    let buffer = fs.readFileSync(DATA_PATH,'utf8');
    let data = JSON.parse(buffer);
    res.json(data)
});

module.exports = router;
  1. 在主文件(app.js)中引入路由文件,并将其注册到 Express 应用程序中。可以插入以下代码
const readMqtt = require('./routes/readMqtt');
// 注册该路由
app.use('/readMqtt', readMqtt);
  1. 最终app.js文件如下
const express = require('express');
const app = express();
app.get('/', (req, res) => { res.send('Hello World!'); });
const readMqtt = require('./routes/readMqtt');
// 注册该路由
app.use('/readMqtt', readMqtt);
app.listen(3000, () => { console.log('Server is running on port 3000.'); });
  1. 在浏览器中访问访问 http://localhost:3000/readMqtt 就可以看到转换后的数据啦。

可能遇到的问题

前端调用时可能会报跨域的错误,Node.js 可以通过设置 HTTP 响应头来支持跨域请求。以下是两种常用的设置方式:

  1. 使用 CORS 中间件

可以使用 cors 中间件来处理跨域请求,使用方法如下:

const express = require('express');
const cors = require('cors');

const app = express();
app.use(cors()); // 允许所有源的请求 

// 或者指定允许的源 
const corsOptions = { origin: 'http://example.com' };
app.use(cors(corsOptions));

上述代码中,我们首先引入了 cors 模块,并在应用程序中使用了该模块作为中间件。默认情况下, cors 中间件会允许所有源的请求。如果需要指定允许的源,可以通过传递一个配置对象来实现。

  1. 手动设置响应头

也可以手动设置响应头来支持跨域请求,示例如下: const express = require('express'); const app = express();

app.get('/', (req, res) => { res.header('Access-Control-Allow-Origin', '*'); // 允许所有源的请求 // res.header('Access-Control-Allow-Origin', 'example.com'); // 指定允许的源 res.send('Hello World!'); });

app.listen(3000, () => { console.log('Server is running on port 3000.'); });

const express = require('express');
const app = express();

app.get('/', (req, res) => {
    res.header('Access-Control-Allow-Origin', '*'); // 允许所有源的请求
    // res.header('Access-Control-Allow-Origin', 'http://example.com'); // 指定允许的源
    res.send('Hello World!');
});

app.listen(3000, () => {
    console.log('Server is running on port 3000.');
});

上述代码中,在处理请求时,我们手动设置了 Access-Control-Allow-Origin 响应头,允许所有源的请求。如果需要指定允许的源,可以将 * 替换为具体的域名。

小结

代码到这里,前端对接MQTT数据库就完成了,如果要应用到实际项目中,可以将node服务部署到windows或Linux的公网服务器上,同时node服务也支持https协议,具体如何配置在这里就不过多阐述了。