vue2、vue3中使用pb(Base64编码)

/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

配置

  1. vue.config.js
arduino 复制代码
chainWebpack: config => {
    ......
    // 添加对 .proto 文件的支持
    config.module
        .rule('proto')
        .test(/\.proto$/)
        .use('raw-loader')
        .loader('raw-loader')
        .end();
},
  1. vite.config.js
vbnet 复制代码
assetsInclude: ['**/*.proto'],

使用

csharp 复制代码
await protoParser.init(); //页面初始化时执行
// 确保 protoParser 已初始化
protoParser.ensureInitialized();
// 解析数据
const SpeakMsgRes = protoParser.decodeMessage('Person', res.data);
console.log('聊天消息:', SpeakMsgRes);
相关推荐
Fantasydg21 分钟前
Request Response对象
前端
Wect23 分钟前
学习React-DnD:核心组件与Hooks
前端
humors22128 分钟前
前端开发案例(不定期更新)
前端·vue.js·elementui·ruoyi·若依
菠萝+冰30 分钟前
npm中-d -g 和默认安装的区别
前端·npm·node.js
一路向北North1 小时前
网页版预编译SQL转换工具
前端·javascript·sql
拿不拿铁192 小时前
Vite 5.x 开发模式启动流程分析
前端
fruge2 小时前
设计稿还原技巧:解决间距、阴影、字体适配的细节问题
前端·css
BBB努力学习程序设计2 小时前
了解响应式Web设计:viewport网页可视区域
前端·html
zhangyao9403302 小时前
uni-app scroll-view特定情况下运用
前端·javascript·uni-app
码农张2 小时前
从原理到实践,吃透 Lit 响应式系统的核心逻辑
前端