背景
公司是做数字孪生可视化的,有一个以B/S架构为基础,围绕数字孪生全要素场景,帮助用户轻松快速构建专业级数字孪生应用的专用产品。
需求
客户有MQTT数据库,需要在我们产品上面对接指标数据,由于前端通常无法直接对接MQTT数据库,因为MQTT是一种基于发布/订阅模式的轻量级通信协议,主要用于物联网设备间的通信,需要在后端实现MQTT协议的客户端,然后通过后端服务器提供的API或WebSocket等方式向前端传输数据。
实现
本次使用Node.js作为后端来读取MQTT的数据,然后将其转换成API接口的形式返回给前端。
前期准备
前期准备包括以下两个步骤:
- 创建一个Node.js服务。
- 与客户确认MQTT数据中台的地址、端口号、用户名、密码和订阅话题等信息。
搭建Node服务
- 安装Node.js,可以从官网下载安装包并按照提示安装。
- 在本地创建一个项目文件夹,并在终端中进入该文件夹。
- 运行
npm init
命令来初始化项目,并生成package.json
文件。 - 安装
express
框架:npm install express --save
。 - 创建一个名为
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!" 字样。
- 在终端中运行
node app.js
命令启动服务。
连接MQTT数据库
- 在node根目录创建一个subscribe.js文件
- 插入以下代码
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);
});
- 最后,在终端中运行
node subscribe.js
启动服务。就可以在根目录看到my.json文件并且已经把数据写入了。 - 至此,mqtt数据读取并保存到本地已结束。
转换成API接口
- 在搭建node服务时已经安装了Express框架,这里使用Express创建路由。
- 创建路由文件并编写路由处理函数。例如,在
/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;
- 在主文件(
app.js
)中引入路由文件,并将其注册到 Express 应用程序中。可以插入以下代码
const readMqtt = require('./routes/readMqtt');
// 注册该路由
app.use('/readMqtt', readMqtt);
- 最终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.'); });
- 在浏览器中访问访问
http://localhost:3000/readMqtt
就可以看到转换后的数据啦。
可能遇到的问题
前端调用时可能会报跨域的错误,Node.js 可以通过设置 HTTP 响应头来支持跨域请求。以下是两种常用的设置方式:
- 使用 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
中间件会允许所有源的请求。如果需要指定允许的源,可以通过传递一个配置对象来实现。
- 手动设置响应头
也可以手动设置响应头来支持跨域请求,示例如下: 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协议,具体如何配置在这里就不过多阐述了。