/proto/chat.proto 文件
syntax = "proto3"
// 定义Protobuf的包名称空间,通过指定包名来避免message名字冲突
package com.xxx.protobuf.model
// 指定生成的Java类的包名。若不指定该选项,则会以头部声明中的package作为Java类的包名。
option java_package = "com.xxx.protobuf.model"
// 指定生成Java类的打包方式。不指定则默认false,表示所有的消息都作为内部类,打包到一个外部类中。true表示一个消息对应一个Java的POJO类
option java_multiple_files = false
// 指定生成的外部类名
option java_outer_classname = "ChatProtos"
message Person {
string name = 1
int32 id = 2
string email = 3
}
message User {
string name = 1
int32 id = 2
string email = 3
}
/utils/protoParser.js 文件
import protobuf from 'protobufjs';
class ProtoParser {
constructor() {
this.root = null;
this.loaded = false;
}
async init() {
if (this.loaded) return;
try {
this.root = protobuf.parse(ChatProto, { keepCase: true }).root;
this.loaded = true;
console.log('Proto 文件加载成功');
} catch (error) {
console.error('Proto 文件解析失败:', error);
throw error;
}
}
async ensureInitialized() {
if (!this.loaded) {
await this.init();
}
}
decodeMessage(type, msg) {
try {
let buffer;
const binaryString = atob(msg);
buffer = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
buffer[i] = binaryString.charCodeAt(i);
}
const MessageType = this.root.lookupType(`com.xxx.protobuf.model.${type}`);
const message = MessageType.decode(buffer);
const object = MessageType.toObject(message, {
longs: String,
enums: String,
bytes: String,
defaults: true,
arrays: true,
objects: true,
oneofs: true
});
return object;
} catch (error) {
console.error(`解析消息类型 ${type} 失败:`, error,':msg:',msg);
throw error;
}
}
async encodeMessage(type, object) {
await this.ensureInitialized();
try {
const MessageType = this.root.lookupType(`com.xxx.protobuf.model.${type}`);
const errMsg = MessageType.verify(object);
if (errMsg) {
console.warn(`验证消息 ${type} 失败:`, errMsg);
}
const message = MessageType.create(object);
const buffer = MessageType.encode(message).finish();
return buffer;
} catch (error) {
console.error(`编码消息类型 ${type} 失败:`, error);
throw error;
}
}
async encodeMessageToBase64(type, object) {
await this.ensureInitialized();
try {
const buffer = await this.encodeMessage(type, object);
return this.arrayBufferToBase64(buffer);
} catch (error) {
console.error(`编码消息为 Base64 失败:`, error);
throw error;
}
}
arrayBufferToBase64(buffer) {
let binary = '';
const bytes = new Uint8Array(buffer);
for (let i = 0; i < bytes.byteLength; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
}
base64ToArrayBuffer(base64) {
const binaryString = atob(base64);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes;
}
}
export default new ProtoParser();
安装protobufjs
npm i protobufjs -D
配置
- vue.config.js
chainWebpack: config => {
......
config.module
.rule('proto')
.test(/\.proto$/)
.use('raw-loader')
.loader('raw-loader')
.end();
},
- vite.config.js
assetsInclude: [
使用
await protoParser.init();
protoParser.ensureInitialized();
const SpeakMsgRes = protoParser.decodeMessage('Person', res.data);
console.log('聊天消息:', SpeakMsgRes);