protobuf.js

protobuf.js,第1张

1.什么是protobuf

协议缓冲区提供了一种语言中立、平台中立、可扩展的机制,用于以向前兼容和向后兼容的方式序列化结构化数据。它类似于 JSON,只是它更小更快,并且生成本地语言绑定

2.protobuf解决了哪些问题

协议缓冲区为大小高达几兆字节的类型化结构化数据包提供了一种序列化格式。该格式适用于临时网络流量和长期数据存储
协议缓冲区是 Google 最常用的数据格式。它们广泛用于服务器间通信以及磁盘上数据的归档存储

3.序列化和反序列化

序列化和反序列化概念
  • 序列化:把对象转换为字节序列的过程称为对象的序列化。
  • 反序列化:把字节序列恢复为对象的过程称为对象的反序列化。
什么情况下需要序列化
  • 当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
  • 当你想用套接字在网络上传送对象的时候。
如何实现序列化

主流序列化协议:xml、json、protobuf

  • XML :指可扩展标记语言,是一种通用和重量级的数据交换格式。以文本结构存储。
  • JSON:是一种通用和轻量级的数据交换格式。以文本结构存储。
  • Protobuf:是Google的一种独立和轻量级的数据交换格式。以二进制结构进行存储。

通用:协议是标准的,不同的第三方软件都可以进行相互序列化和反序列化
独立:标准是私有的,比如:protocol buffer协议,目前只有Google自家支持
文本格式:可以看出内容的具体文字含义,比如:“address”: “liulina”
二进制格式:纯数值的数据,可读性不强

4.JSON、XML、Protobuf对比
  • 速度:protobuf > json > xml
  • 序列化后数据大小:protobuf < json < xml
  • 宽带计算对比:protobuf < json < xml
5.语言指南

参考链接

message SearchRequest {
  required string query = 1;
  optional int32 page_number = 2;
  optional int32 result_per_page = 3 [default = 10];
  enum Corpus {
    UNIVERSAL = 0;
    WEB = 1;
    IMAGES = 2;
    LOCAL = 3;
    NEWS = 4;
    PRODUCTS = 5;
    VIDEO = 6;
  }
  optional Corpus corpus = 4 [default = UNIVERSAL]
}

指定字段类型:更多类型

  • 字段类型:string、int32
  • 字段规则:
    1.required:格式良好的消息必须恰好具有该字段之一
    2.optional:一个格式良好的消息可以有零个或一个这个字段(但不能超过一个)
    3.repeated:该字段可以在格式良好的消息中重复任意次数(包括零次)。重复值的顺序将被保留。
  • 字段编号:(1、2、3)消息定义中的每个字段都有一个唯一的编号。这些数字用于在 消息二进制格式中标识您的字段,并且一旦您的消息类型在使用中就不应更改

SearchRequest两个(page_number和result_per_page)整数类型和一个(query)字符串类型
result_per_page字段默认值为10
Corpus:枚举

扩展

message SearchRequest {
  // ...
  extensions 100 to 199;
}

这表示字段编号 [100, 199] 的范围Foo是为扩展保留的。其他用户现在可以使用指定范围内的字段编号Foo在他们自己的.proto导入您的文件中添加新字段.proto- 例如:

extend SearchRequest {
  optional int32 bar = 126;
}

这会将一个以bar字段编号 126 命名的字段添加到 的原始定义中SearchRequest。

选项
  • java_package(文件选项):

要用于生成的 Java 类的包。如果文件中没有给出明确java_package的选项.proto ,那么默认情况下将使用 proto 包(使用文件中的“package”关键字指定.proto)。但是,proto 包通常不能制作好的 Java 包,因为不期望 proto 包以反向域名开头。如果不生成 Java 代码,则此选项无效。

option java_package = "com.example.foo";
  • java_outer_classname(文件选项):

您要生成的包装 Java 类的类名(以及文件名)。如果文件中没有明确 java_outer_classname指定,.proto则将通过将.proto文件名转换为驼峰式来构造类名(因此 foo_bar.proto变为FooBar.java)

option java_outer_classname = "Ponycopter";
  • java_multiple_files(文件选项):

如果为 false,则只会.java为此文件生成一个.proto文件,以及所有 Java 类/枚举/等。为顶级消息、服务和枚举生成的将嵌套在外部类中(请参阅 参考资料 java_outer_classname)。如果为 true,.java将为每个 Java 类/枚举/等生成单独的文件。为顶级消息、服务和枚举生成,并且为此.proto文件生成的包装 Java 类将不包含任何嵌套类/枚举/等。这是一个布尔选项,默认为false

option java_multiple_files = true;
protobuf.js

protobuf.js

消息类
  • Message.verify (message: Object):null|string

验证纯 JavaScript 对象是否满足有效消息的要求,因此可以毫无问题地进行编码。如果有错误,它不是抛出,而是将错误消息作为字符串返回

let payload = "invalid (not an object)";
let err = AwesomeMessage.verify(payload);
if (err)
  throw Error(err);
  • Message.encode (message: Message|Object[, writer: Writer]):

对消息实例或有效的纯 JavaScript 对象进行 编码。此方法不会隐式验证消息,并由用户确保有效负载是有效消息。

let buffer = AwesomeMessage.encode(message).finish();
  • Message.encodeDelimited(message: Message|Object [, writer: Writer]):

Writer工作方式类似Message.encode但另外将消息的长度作为 varint。

  • Message.decode (reader: Reader|Uint8Array):

Message将缓冲区解码为消息实例。如果缺少必填字段,它会抛出一个util.ProtocolError属性instance设置为到目前为止解码的消息。如果有线格式无效,它会抛出一个Error.

try {
  var decodedMessage = AwesomeMessage.decode(buffer);
} catch (e) {
    if (e instanceof protobuf.util.ProtocolError) {
      // 实例保存到目前为止已解码的消息,其中缺少必填字段
    } else {
      // wire格式无效
    }
}
  • Message.decodeDelimited (reader: Reader|Uint8Array):

Message工作方式类似Message.decode,但额外读取作为 varint 前缀的消息的长度。

  • Message.create (properties: Object):

从一组满足有效消息要求的属性中Message创建一个新的消息实例。在适用的情况下,建议优先使用Message.create,Message.fromObject因为它不会执行可能的冗余转换。

let message = AwesomeMessage.create({ awesomeField: "AwesomeString" });
  • Message.fromObject(object: Object):

将任何无效的纯 JavaScript 对象转换为消息实例

// 将 awesomeField 转换为字符串
let message = AwesomeMessage.fromObject({ awesomeField: 42 });
  • Message.toObject(message: Message [, options: ConversionOptions]):

将消息实例转换为任意纯 JavaScript 对象,以便与其他库或存储进行互 *** 作。根据指定的实际转换选项,生成的纯 JavaScript 对象可能仍满足有效消息的要求,但大多数情况下它不满足

var object = AwesomeMessage.toObject(message, {
  enums: String,  // 枚举作为字符串名称
  longs: String,  // longs 作为字符串 (需要 long.js)
  bytes: String,  // 字节作为 base64 编码的字符串
  defaults: true, // 包括默认值
  arrays: true,   // 即使 defaults=false 也填充空数组(重复字段)
  objects: true,  // 填充空对象(映射字段),即使 defaults=false 
  oneofs: true    // 包括设置为当前字段名称的虚拟 oneof 字段
});

使用.proto 文件

package awesomepackage;
syntax = "proto3";
// 指定你正在使用 proto3 语法
// 若不设置,protocol buffer编译器会默认为您使用的是 proto2 
message AwesomeMessage {
    string awesome_field = 1;
 }
protobuf.load("awesome.proto", function(err, root) {
    if (err)
        throw err;

    // 获取消息类型
    var AwesomeMessage = root.lookupType("awesomepackage.AwesomeMessage");

    // 典型有效载荷
    var payload = { awesomeField: "AwesomeString" };

    // 如有必要(即可能不完整或无效时)验证有效载荷
    var errMsg = AwesomeMessage.verify(payload);
    if (errMsg)
        throw Error(errMsg);

    // 创建新消息
    var message = AwesomeMessage.create(payload); //如果需要转换,或者使用fromObject,

    // 将消息编码到UINT8阵列(浏览器)或缓冲区(节点)
    var buffer = AwesomeMessage.encode(message).finish();
    // ... 

    // 将UINT8阵列(浏览器)或缓冲区(节点)解码为消息
    var message = AwesomeMessage.decode(buffer);
    // ... 

    // 如果应用程序使用长度分隔的缓冲区,则还有encodeDelimited和decodeDelimited。

    // 可能会将消息转换回普通对象
    var object = AwesomeMessage.toObject(message, {
        longs: String,
        enums: String,
        bytes: String,
        //参见转换选项
    });
});
axios使用protobuf进行通讯
  1. 安装并引入protobufjs
yarn add protobufjs

// 创建proto.js文件
import ProtoBuf from "protobufjs";

2.建立proto文件用于存放相关文件

  • 创建.proto文件
syntax = "proto3";
option java_package = "probofu.Controllers";
option java_outer_classname = "Controllers";
message Address {
  string id = 1;
  string name = 2;
}

3.解析.proto文件
package.json中添加生成proto.js文件的命令

"scripts": {
    "buildproto": "pbjs -t json src/proto/chat.proto >   src/proto/chat.proto.json"
}

4.执行 yarn buildproto命令生成.proto.json文件
5.引用生成的js文件发送请求

import ProtoBuf from "protobufjs";
import fileProto from "@/configFile/proto/proto.json";

const root = ProtoBuf.Root.fromJSON(fileProto);
let userInfo = root.lookupType("Person");
let BaseResponse = root.lookupType("BaseResponse");
let infoData = {Name:'xiaoming',Id:24};
 // 将js对象序列化成二进制
let infoEncodeMessage = userInfo
   .encode(userInfo.create(infoData))
   .finish();
let blob = new Blob([infoEncodeMessage], {type: 'buffer'});
 // 新建一个axios对象
const httpService = axios.create({
  timeout: 45000,
  method: "post",
  headers: {
    "X-Requested-With": "XMLHttpRequest",
    "Content-Type": "application/octet-stream"
  },
  responseType: "arraybuffer"
});
httpService.post("url",blob)
  .then(e => {
    // 将二进制数据生成js对象
    const buf = protobuf.util.newBuffer(e.data);
    let res = BaseResponse.decode(buf);
    let person = userInfo.decode(res.data.value);
  });

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/790211.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-05
下一篇 2022-05-05

发表评论

登录后才能评论

评论列表(0条)

保存