/proto/chat.proto 文件
ini
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 文件
typescript
// src/utils/protoParser.js
import protobuf from 'protobufjs';
// vue2 import ChatProto from '@/proto/chat.proto';
// vue3 import ChatProto from '../proto/chat.proto?raw';
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;
}
}
// 编码消息并返回 base64 字符串(与安卓端格式一致)
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;
}
}
// ArrayBuffer 转 Base64
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);
}
// Base64 转 ArrayBuffer
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
css
npm i protobufjs -D
配置
- vue.config.js
arduino
chainWebpack: config => {
......
// 添加对 .proto 文件的支持
config.module
.rule('proto')
.test(/\.proto$/)
.use('raw-loader')
.loader('raw-loader')
.end();
},
- vite.config.js
vbnet
assetsInclude: ['**/*.proto'],
使用
csharp
await protoParser.init(); //页面初始化时执行
// 确保 protoParser 已初始化
protoParser.ensureInitialized();
// 解析数据
const SpeakMsgRes = protoParser.decodeMessage('Person', res.data);
console.log('聊天消息:', SpeakMsgRes);