protobuf.js是一个纯JavaScript实现,支持Node.js和浏览器的TypeScript,它容易使用速度快速,可以直接反射.proto
文件,不需要生成任何文件。
protobuf.js是基于ByteBuffer.js的Protocol Buffers纯JavaScript实现,主要功能是解析.proto文件,构建Message类,编码解码。
安装
下载安装protobufjs
https://github.com/protobufjs/protobuf.js
查看protobufjs候选版本
$ npm view protobufjs versions
使用NPM全局安装protobufjs
$ npm i -g protobufjs
protobuf.js 依赖 long.js、bytebuffer.js
创建.proto
文件
$ vim msg.proto
syntax = "proto3";
package ns;
message Login {
string name = 1;
string pwd = 2;
}
message Address{
required string province = 1;
required string city = 2;
required string country = 3;
}
转换
在命令行模式下,pbjs命令用于在文件格式之间转换,并可以生成静态代码。
$ pbjs
protobuf.js v6.7.0 CLI for JavaScript
在文件格式之间转换并生成静态代码
-t, --target 指定目标格式,可以接受需要自定义目标的路径。
json JSON
json-module JSON表示为模块
proto2 Protocol Buffers, Version 2
proto3 Protocol Buffers, Version 3
static 无反射的静态代码(本身不起作用)
static-module 无反射模块的静态代码
-p, --path 将某个目录添加到包含路径中
-o, --out 保存文件而非写入到标准输出
--sparse 只导出从主文件引用的类型(实验)
仅限模块目标:
-w, --wrap 指定要使用的包装器,可接受需要自定义包装器的路径。
default 默认包装器支持CommonJS与AMD标准
commonjs CommonJS包装器
amd AMD包装器
es6 ES6包装器
closure 添加到全局protobuf的protobuf.roots上的闭包
--dependency 指定protobuf版本,可接受有效的模块ID。
-r, --root 指定备用的protobuf.roots名称
-l, --lint Linter配置,默认protbuf.js兼容规则:
eslint-disable block-scoped-var, id-length,
no-control-regex, no-magic-numbers, no-prototype-builtins,
no-redeclare, no-shadow, no-var, sort-vars
--es6 启用ES6语法
仅限原始源:
--keep-case 保留字段大小写而非是转换为驼峰大小写
仅限静态目标:
--no-create 不生成用于反射兼容性的创建函数.
--no-encode 不生成编码函数.
--no-decode 不生成解码函数.
--no-verify 不生成验证函数.
--no-convert 不生成转换函数
--no-delimited 不生成风格的编码/解码函数.
--no-beautify 不美化生成的代码.
--no-comments 不输出任何JSDoc注释.
--force-long 强制对s-/u-/int64和s-/fixed64字段使用Long
--force-number 强制对s-/u-/int64和s-/fixed64字段使用number
--force-message 强制使用消息而非普通对象
usage: pbjs [options] file1.proto file2.json ... (or pipe) other | pbjs [options] -
文件转换
使用pbjs
命令将.proto
文件转换为.json
文件
$ ./node_modules/protobufjs/bin/pbjs -t json msg.proto > msg.json
使用pbjs
命令将.proto
文件转换为.js
文件
$ ./node_modules/protobufjs/bin/pbjs -t static_module -w commonjs -o msg.js msg.proto
编写pbjs命令的转换脚本
$ vim pbjs.cmd
::判断当前目录是否存在node.exe
@IF EXIST "%~dp0\node.exe" (
::使用node执行pbjs进行文件转换
"%~dp0\node.exe" "%~dp0\..\protobufjs\bin\pbjs" %*
) ELSE (
@SETLOCAL
::将环境变量PATHEXT中的JS删除
@SET PATHEXT=%PATHEXT:;.JS;=;%
::使用node执行pbjs进行文件转换
node "%~dp0\.. \protobufjs\bin\pbjs" %*
)
使用
由于JavaScript是一种动态类型语言, protobuf.js引入有效消息的概念,以便提供最佳的性能。
不同方法与有效消息之间的关系
方法 | 描述 |
---|---|
Message.verify(message:Object):null|string | 验证普通JavaScript对象是否满足有效消息的要求,以确保无错误的进行加密编码(encode)。verify不抛出错误而会将错误消息作为字符串返回。 |
Message.encode(message:Message|Object [, writer:Writer]):Writer | 对消息实例或有效的纯JavaScript对象进行编码,encode不隐式的验证消息,而由用户确定有效负载是有效消息。 |
Message.encodeDelimited(message:Message|Objecct [, writer:Writer]):Writer | 将protobuffer解码为消息实例,如果required字段缺少则会抛出util.ProtocolError错误。 |
Message.decodeDelimited(reader:Reader|Uint8Array):Message | 工作方式类似于decode函数,会另外读取一个消息的长度作为变量的预设值。 |
Message.create(properties:Object):Message | 从一组满足有效消息要求的属性中创建一个新消息实例,如果适用,建议首选create而非fromObject,因为create不会执行可能存在冗余的转换。 |
Message.fromObject(object:Object):Message | 将任何无效的纯JavaScript对象转换为消息实例 |
Message.toObject(message:Message [, options:ConversionOptions]):Object | 将消息实例转换为任意纯JavaScript对象,以便与其它库或存储进行互操作。根据指定的实际转换选项,生成纯JavaScript对象。 |
初始化
$ npm i -g require
let pbroot = require("protobufjs").Root;
let json = require("msg.json");
let root = pbroot.fromJSON(json);
let Message = root.lookupType("ns.Address");
创建
Message.create(properties:Object):Message
从一组满足有效消息要求的属性中创建一个新消息实例,如果适用,建议首选create而非fromObject,因为create不会执行可能存在冗余的转换。
例如;
//数据
let data = {province:"", city:"", area:""};
data.province = "hunan";
data.city = "changsha";
data.area = "yuelu";
//创建
let message = Message.create(data);
console.log(message);//Address {province: "hunan", city: "changsha", area: "yuelu"}
验证
Message.verify(message:Object):null|string
验证普通JavaScript对象是否满足有效消息的要求,以确保无错误的进行加密编码(encode)。
verify不抛出错误而会将错误消息作为字符串返回。
let message = Message.create({province:"hunan"});
let errmsg = Message.verify(message);
if(errmsg){
throw Error(errmsg);
}
序列化编码
Message.encode(message: Message|Object [, writer: Writer]): Writer
对消息实例或有效的纯JavaScript对象进行编码,encode不隐式的验证消息,而由用户确定有效负载是有效消息。
let data = {};
data.province= "hunan";
data.city = "changsha";
let buffer= Message.encode(Message.create(data)).finish();
反序列化解码
Message.decode(reader: Reader|Uint8Array): Message
将protobuffer解码为消息实例,如果缺乏required字段则抛出util.ProtocolError错误,如果wire格式无效也会抛出错误。
//解码
try{
let message = Message.decode(buffer);
}catch(e){
if(e instanceof protobuf.util.ProtocolError){
//missing required field
}else{
//wire format is invalid
}
}