protobuf.js是一個純JavaScript實現(xiàn),支持Node.js和瀏覽器的TypeScript棚愤,它容易使用速度快速骏庸,可以直接反射.proto
文件髓涯,不需要生成任何文件袒啼。
protobuf.js是基于ByteBuffer.js的Protocol Buffers純JavaScript實現(xiàn),主要功能是解析.proto文件,構(gòu)建Message類瘤泪,編碼解碼灶泵。
window 下
1,下載用來生成web js文件的工具
protoc-gen-grpc-web
下地地址:https://github.com/grpc/grpc-web/releases
選擇:protoc-gen-grpc-web-1.3.1-windows-x86_64.exe 即可
下載完成后改名為protoc-gen-grpc-web.exe并移動到項目里,和proto文件存放在同一目錄下
2,下載protoc.exe執(zhí)行程序下載地址protoc.exe
https://github.com/protocolbuffers/protobuf/releases
選擇protoc-3.20.1-win32.zip
下載后解壓就行对途,然后把bin文件夾里面的protoc.exe路徑加入到環(huán)境變量赦邻。
找到環(huán)境變量,系統(tǒng)變量->Path->新建->復(fù)制bin文件夾的路徑实檀,然后一直點確定退出即可惶洲。
把protoc.exe拷貝到C:\Windows\System32路徑下。
調(diào)用cmd膳犹,輸入protoc發(fā)現(xiàn)提示missing input file恬吕,證明已經(jīng)可以使用了。
3, 進入到proto文件所在目錄的cmd執(zhí)行命令
protoc -I=./ ./engine_service.proto --js_out=import_style=commonjs:./ --plugin=protoc-gen-grpc=./protoc-gen-grpc-web.exe --grpc-web_out=import_style=commonjs,mode=grpcwebtext:./
該命令是將engine_service.proto文件生成js文件
生成其他文件只需替換文件名即可
示例:
engine_service.proto文件生成了兩個對應(yīng)的js文件
node 安裝
下載安裝protobufjs
https://github.com/protobufjs/protobuf.js
查看protobufjs候選版本
$ npm view protobufjs versions
使用NPM全局安裝protobufjs
$ npm i -g protobufjs
protobuf.js 依賴 long.js须床、bytebuffer.js
創(chuàng)建.proto
文件
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;
}
這個是使用cim框架時候?qū)嶋H使用中有map類
syntax = "proto3";
package com.model.proto;
option java_outer_classname="ReplyBodyProto";
message Model {
string key = 1;
string code = 2;
string message = 3;
int64 timestamp =4;
map<string,string> data =5;
}
轉(zhuǎn)換
在命令行模式下铐料,pbjs命令用于在文件格式之間轉(zhuǎn)換,并可以生成靜態(tài)代碼豺旬。
$ pbjs
protobuf.js v6.7.0 CLI for JavaScript
在文件格式之間轉(zhuǎn)換并生成靜態(tài)代碼
-t, --target 指定目標(biāo)格式钠惩,可以接受需要自定義目標(biāo)的路徑。
json JSON
json-module JSON表示為模塊
proto2 Protocol Buffers, Version 2
proto3 Protocol Buffers, Version 3
static 無反射的靜態(tài)代碼(本身不起作用)
static-module 無反射模塊的靜態(tài)代碼
-p, --path 將某個目錄添加到包含路徑中
-o, --out 保存文件而非寫入到標(biāo)準(zhǔn)輸出
--sparse 只導(dǎo)出從主文件引用的類型(實驗)
僅限模塊目標(biāo):
-w, --wrap 指定要使用的包裝器族阅,可接受需要自定義包裝器的路徑篓跛。
default 默認(rèn)包裝器支持CommonJS與AMD標(biāo)準(zhǔn)
commonjs CommonJS包裝器
amd AMD包裝器
es6 ES6包裝器
closure 添加到全局protobuf的protobuf.roots上的閉包
--dependency 指定protobuf版本,可接受有效的模塊ID坦刀。
-r, --root 指定備用的protobuf.roots名稱
-l, --lint Linter配置愧沟,默認(rèn)protbuf.js兼容規(guī)則:
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 保留字段大小寫而非是轉(zhuǎn)換為駝峰大小寫
僅限靜態(tài)目標(biāo):
--no-create 不生成用于反射兼容性的創(chuàng)建函數(shù).
--no-encode 不生成編碼函數(shù).
--no-decode 不生成解碼函數(shù).
--no-verify 不生成驗證函數(shù).
--no-convert 不生成轉(zhuǎn)換函數(shù)
--no-delimited 不生成風(fēng)格的編碼/解碼函數(shù).
--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] -
文件轉(zhuǎn)換
使用pbjs
命令將.proto
文件轉(zhuǎn)換為.json
文件
#老版本
./node_modules/protobufjs/bin/pbjs -t json msg.proto > proto.js
#新版本
npx pbjs -t json message.proto --es6 "proto.js"
npx pbjs -t json message.proto --ts "proto.ts"
得到的msg.js文件是json格式
在前面加上module.exports =
例如:
module.exports ={
js文件的全部內(nèi)容
"nested": {
"com": {
"nested": {
"farsunset": {
"nested": {
"cim": {
"nested":
……………………省略
}
使用pbjs
命令將.proto
文件轉(zhuǎn)換為.js
文件
$ ./node_modules/protobufjs/bin/pbjs -t static_module -w commonjs -o msg.js msg.proto
編寫pbjs命令的轉(zhuǎn)換腳本
$ vim pbjs.cmd
::判斷當(dāng)前目錄是否存在node.exe
@IF EXIST "%~dp0\node.exe" (
::使用node執(zhí)行pbjs進行文件轉(zhuǎn)換
"%~dp0\node.exe" "%~dp0\..\protobufjs\bin\pbjs" %*
) ELSE (
@SETLOCAL
::將環(huán)境變量PATHEXT中的JS刪除
@SET PATHEXT=%PATHEXT:;.JS;=;%
::使用node執(zhí)行pbjs進行文件轉(zhuǎn)換
node "%~dp0\.. \protobufjs\bin\pbjs" %*
)
使用
由于JavaScript是一種動態(tài)類型語言, protobuf.js引入有效消息的概念鲤遥,以便提供最佳的性能沐寺。
不同方法與有效消息之間的關(guān)系
方法 | 描述 | |
---|---|---|
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函數(shù),會另外讀取一個消息的長度作為變量的預(yù)設(shè)值懈涛。 |
Message.create(properties:Object):Message | 從一組滿足有效消息要求的屬性中創(chuàng)建一個新消息實例逛万,如果適用,建議首選create而非fromObject,因為create不會執(zhí)行可能存在冗余的轉(zhuǎn)換宇植。 | |
Message.fromObject(object:Object):Message | 將任何無效的純JavaScript對象轉(zhuǎn)換為消息實例 | |
Message.toObject(message:Message [, options:ConversionOptions]):Object | 將消息實例轉(zhuǎn)換為任意純JavaScript對象得封,以便與其它庫或存儲進行互操作。根據(jù)指定的實際轉(zhuǎn)換選項指郁,生成純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");
創(chuàng)建
Message.create(properties:Object):Message
從一組滿足有效消息要求的屬性中創(chuàng)建一個新消息實例,如果適用闲坎,建議首選create而非fromObject疫粥,因為create不會執(zhí)行可能存在冗余的轉(zhuǎn)換。
例如;
//數(shù)據(jù)
let data = {province:"", city:"", area:""};
data.province = "hunan";
data.city = "changsha";
data.area = "yuelu";
//創(chuàng)建
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
}
}