1. 程式人生 > 實用技巧 >web前端 js環境 使用 protobuf google-protobuf

web前端 js環境 使用 protobuf google-protobuf

google-protobuf 官網地址https://developers.google.com/protocol-buffers/

  網上有些封裝過後支援前端使用的 google-protobu f庫,比如protobufjs ,不過看了下不太喜歡...

  感覺就還是使用google-protobuf 官網提供的比較舒心!

一、安裝protoc編譯器

  官網下載地址:https://github.com/protocolbuffers/protobuf/releases

  開啟網址:

  下拉:

  本來打算直接下載protobuf-all-3.14.0.zip 壓縮包,畢竟誰在乎佔用那幾M大小嘛...安裝了,能編譯成對應的JS、GO等等就比較好...

  結果不行:

  編譯是用的一個 protoc.exe 可執行檔案,這裡面就沒有。

  要下載對應系統的壓縮包!

  下載protoc-3.14.0-win64.zip (對應自己的系統),解壓,進入 bin 資料夾就發現 protoc.exe 檔案了:

  現在就可以用這個protoc.exe 編譯檔案了。可以每次進到這個目錄執行,也可以加入環境變數,就可以在自己的專案編輯器裡面直接使用。

二、根據 *.proto 檔案,編譯為對應語言的檔案

直接在目錄位置輸入 cmd 然後回車 開啟在當前目錄的命令列工具

輸入編譯命令:

  protoc*.proto--js_out=import_style=commonjs,binary:../pb
  說明:     *.proto      選中當前目錄的所有後綴為 .proto 的檔案(也可以具體的某一個檔案)。如果沒有進到*.proto 檔案所在的目錄,也可以加上路勁:../path1/*.proto 這種。但是如果proto之間有相互引用,就不要加路勁了,引用會報錯。     --js_out      編譯目標為 js 檔案     commonjs     編譯出來的 js 檔案,按照commonjs 匯入使用     binary:./proto-js  編譯的輸出目錄,就是個相對路徑。例如一個點:binary:. 直接編譯到當前目錄。檔案多的時候建一個資料夾(提前建好,不然報錯)來放比較安逸
我放入了一些測試檔案、建了兩資料夾: 只要沒報錯就編譯完成了: 檢視結果:

三、匯入使用

  按照前面的 commonjs 規範,使用 require 匯入:

  

  (proto原始檔可能在編輯器裡會飄紅報錯,不用管它...)

  嗯...使用前先:

    npm igoogle-protobuf

  看一下都有些啥:

  

  可以看到匯入的是一個物件,裡面包含了對應 .proto 檔案所定義的資料結構。它們都掛載有相同的方法,可以看編譯出來的js檔案:

  解密資料:deserializeBinary 內部呼叫的deserializeBinaryFromReader 方法

  加密資料:serializeBinary 內部呼叫的serializeBinaryToWriter 方法

  主要目標:

  1. 建立符合 protobuf 的物件,加密,以便傳輸。
  2. 解密獲取的protobuf 壓縮的資料,解析為 js 物件。

  具體例子:

let proto = require("../pb/conn.int_pb");

const protoObj = new proto.Image()//以 new 的方式建立
console.log(protoObj)//輸出一個物件 可以看到有一個array屬性 array: [] 其實所有的屬性值就會放裡面,沒設定時是空的

//設定對應的屬性 (自己確定好屬性值的型別)
protoObj.setId('123')
protoObj.setWidth(88)
protoObj.setUrl('123')
console.log(protoObj)//可以看到設定的值 array: [ '123', 88, 88, '123' ]

const protoData = protoObj.serializeBinary()//加密
console.log(protoData)//一串Uint8Array陣列值 protobuf 加密過後都是  Uint8Array 型別的資料

const newProtoObj = proto.Image.deserializeBinary(protoData)//解密 必須以對應的資料結構呼叫方法 傳入資料
console.log(newProtoObj)//和 protoObj 資料就一樣了 

console.log(newProtoObj.getId())// "123"
console.log(newProtoObj.getWidth())// 88
console.log(newProtoObj.getHeight())// 0 存在的屬性 但是前面沒有賦值
console.log(newProtoObj.getUrl())// "123"

console.log(newProtoObj.getThumbnailUrl())// "" 存在 但是前面沒有賦值 是個空串
// console.log(newProtoObj.getTThumbnailUrl())//不存在的屬性 報錯 TypeError: newProtoObj.getTThumbnailUrl is not a function

//不存在的屬性都會報錯,存在的屬性都會有對應的預設值
//可以看出來,預設是每個屬性都有對應的 get、set方法

// 設定屬性好像沒有簡便方法,我看了看編譯出來的js檔案,反正我沒瞅見,但是獲取有一個,就是 toObject const jsObj = newProtoObj.toObject()//其實就是呼叫了一遍get方法 //會輸出包含所有屬性的一個js物件,沒有設定的值就是預設值 console.log(jsObj)//直接輸出jsObj { id: '123', width: 88, height: 0, url: '123', thumbnailUrl: '' } // 自己寫一個設定的方法 function formatSetStruct(structType, structData) {//傳入需要的結構型別和對應資料 const newStruct = new proto[structType](); for (let key in structData) {//遍歷設定一遍就好 if (Object.hasOwnProperty.call(structData, key)) { let setKey = "set" + key; newStruct[setKey](structData[key]); } } return newStruct.serializeBinary();//直接返回加密的資料 } const testFormat = formatSetStruct('Image', { Id : '123123adas', //string Width : 123, //int32 Height : 67, //int32 Url : '地址', //string ThumbnailUrl : '縮圖地址', //string }) const testJsObj = proto.Image.deserializeBinary(testFormat).toObject() console.log(testJsObj) // { // id: '123123adas', // width: 123, // height: 67, // url: '地址', // thumbnailUrl: '縮圖地址' // } //但是有些特殊情況, proto裡面設定的 userIds repeated string 到了js這邊 就是 UserIdsList 了 // userIds 屬性對映為了 UserIdsList 需要自己處理

    OK!