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);
相关推荐
程序员黑豆34 分钟前
Java类型推断完全指南:从var到菱形运算符,掌握使用限制与最佳实践
java·前端·ai编程
To_OC1 小时前
踩了个 TS 的坑之后,我终于把 type 和 interface 掰明白了
前端·react.js·typescript
GreenTea1 小时前
深度解读 Anthropic 多智能体报告:更强的模型 ≠ 更好的协调
前端·后端·算法
浮生望2 小时前
前端API工程化:用 Mock 数据与 Axios 配置实现独立于后端的并行开发
前端
万少2 小时前
给 DeepSeek Harness 装个"应用商店":一条命令,595 个插件随你逛
前端·javascript·后端
波波0072 小时前
C# 15 重磅新特性: 带标签 break 与 continue:重新定义嵌套循环控制流
服务器·前端·c#
Brown.alexis3 小时前
es6知识点1-自备使用
前端·ecmascript·es6
小爬的老粉丝4 小时前
JavaScript 纯前端预览 WPS:先识别容器,再路由解析器
前端·javascript·wps
计算机魔术师5 小时前
新兴多智能体系统的模式与问题
前端
用户059540174465 小时前
AI Agent 上下文污染踩坑实录:用 pytest + Redis 揪出 3 类记忆串号 bug,排查 6 小时
前端·css