前端如何处理与 RabbitMQ 通讯时 protobuf 的序列化数据
背景
这次项目需求是要对接到 RabbitMQ
来实时接收数据,在浏览器将数据实时渲染在页面上。
特殊的是,这些数据是经过 protobuf
进行序列化编码的,前端接收到的是进制
数据,所以需要对接收到的数据进行解码
后才能使用。
工具
项目使用的是 StompJs
进行与 RabbitMQ
通讯:
npm install @stomp/stompjs
还需要用到两个工具,用来对接收到的数据进行解码,我们先进行全局安装:
npm i protobufjs protobufjs-cli -g
生成用来解码数据的 JS 文件
在对数据解码之前,后端人员会事先定义好了PB协议,字段内容都在 .proto
文件中,可能会有很多个 .proto
文件,找他们拿到这些文件。
举个例子:
// User.proto
syntax = "proto3";
message User
{
string username = 1;
uint32 age = 2;
}
等号后的值是唯一的标识号,不用管它。
拿到这些 .proto
文件后,在项目 src
目录下新建 proto
文件夹,把所有 .proto
文件都放到文件夹里。
接着在项目根目录执行命令:
pbjs -t json-module -w commonjs -o src/proto/base.js src/proto/*.proto
这条命令会根据目录下的 .proto
文件,输出一个 base.js
的文件,这个 JS 文件就是用来解码的。
成功生成后,大概是长这样子:
"use strict";
var $protobuf = require("protobufjs/light");
var $root = ($protobuf.roots["default"] || ($protobuf.roots["default"] = new $protobuf.Root()))
.addJSON({
User: {
fields: {
username: {
type: "string",
id: 1
},
age: {
type: "uint32",
id: 2
}
}
}
});
module.exports = $root;
到此,前期工作准备完毕!
连接 RabbitMQ
import { Client } from '@stomp/stompjs'
const client = new StompJs.Client({
// URL地址
brokerURL: 'ws://localhost:15674/ws',
connectHeaders: {
// 你的账号
login: 'user',
// 你的密码
passcode: 'password'
}
})
// 注意!!!要记得调用 activate 方法来初始化连接
client.activate()
接着打开控制台,到 Network
的 WS
下刷新页面,选中 ws
可以看到连接成功了!
这里默认发送是数据是心跳机制,就是让对方知道自己还活着,以确保连接的有效性的机制。
订阅消息队列,接收数据
client.onConnect = function(frame) {
// 连接成功后,在这里订阅消息
// 举个例子,订阅 test 队列的消息,实时接收数据
const subscription = client.subscribe(
'/queue/test',
(message) => {
if (message.headers['content-type'] === 'application/octet-stream') {
// 这里接收 进制 数据
// 使用 message.binaryBody
} else {
// 这里接收文本数据
// 使用 message.body
}
},
{} // 这个参数是 headers,根据场景需要填写,默认为空
)
}
当接收到数据,发现是这样的:
这时候就需要用到解码的文件 base.js
,先导入,定义所需的 message
,这里是 User
。
import protoRoot from '@/proto/base'
const User = protoRoot.lookup('User')
接着就可以进行解码数据:
client.onConnect = function(frame) {
// 连接成功后,在这里订阅消息
// 举个例子,订阅 test 队列的消息,实时接收消息
const subscription = client.subscribe(
'/queue/test',
(message) => {
if (message.headers['content-type'] === 'application/octet-stream') {
// 这里接收 进制 数据
// 使用 message.binaryBody
const data = User.decode(message.binaryBody)
console.log(data)
} else {
// 这里接收文本数据
// 使用 message.body
}
},
{} // 这个参数是 headers,根据场景需要填写,默认为空
)
}
打印数据,发现已经自动转成了对象,格式就是 User.proto
文件中定义的那样,现在就可以正常使用接收的数据了。
最后
转载自:https://juejin.cn/post/7210944553276489787