protobuf介紹
由於網上關於protobuf的交互的資料比較零散,所以自己整理了一下關於protobuf前後端交互的資料,以作參考。
Google Protocol Buffers 簡稱 Protobuf,它提供了一種靈活、高效、自動序列化結構數據的機制,可以聯想 XML,但是比 XML 更小、更快、更簡單。僅需要自定義一次你所需的數據格式,然後用戶就可以使用 Protobuf 編譯器自動生成各種語言的源碼,方便的讀寫用戶自定義的格式化的數據。與語言無關,與平臺無關,還可以在不破壞原數據格式的基礎上,依據老的數據格式,更新現有的數據格式。
前後端交互方式
前後端都是以二進制形式進行交互信息。前後端定義proto後綴的文件,以此文件來當文檔來進行溝通。
protobuf文件形式
以下爲protobuf文件的demo,test.proto,文件的結構確實簡單明瞭。
enum FOO {
BAR = 1;
}
message Test {
required float num = 1;
required string payload = 2;
optional string payloads = 3;
}
message AnotherOne {
repeated FOO list = 1;
}
前後端進行protobuf的環境安裝
後端以node爲例子:
安裝bufferhelper以及protocol-buffers進行解析protobuf文件
npm install bufferhelper
npm install protocol-buffers
前端需要安裝解析protobuf的環境。
mac使用brew安裝protobuf環境。此操作需要先安裝Homebrew環境。具體的Homebrew的安裝自行搜索。
windows的前端環境安裝有點不一樣,自行搜索。
brew install protobuf
測試前端proto環境是不是安裝好了,如果有版本就是安裝好了。
protoc --version
在進行前後端交互之前,前端需要進行編譯proto文件。
test.proto爲前端以及後端相同的proto文件。先編譯爲js文件再執行。首先進入node項目的proto的目錄下面,執行下面的命令之後會生成test_pb.js文件。最後js只需要解析這個文件即可。前端也需要執行這樣的操作,因爲我這邊是前後端分離的。是兩個項目,所以兩個項目都需要編譯。
protoc --js_out=import_style=commonjs,binary:. test.proto
後端給前端傳數據
後端賦值proto文件的內容並傳給前端。
後端傳protobuf二進制給前端,要先轉化爲json纔可以給前端。不然的話前端會轉化成亂碼的。前端需要請求此路由。
app.get('/proto/get', function (req, res) {
let protobuf = require('protocol-buffers')
let messages=protobuf(fs.readFileSync('./proto/test.proto')
let buf = messages.Test.encode({
num: 42,
payload: 'hello world node js and javahhh呵呵呵',
payloads: ''
})
console.log(buf) // 打印出來的是二進制流
res.send(JSON.stringify(buf)); //需要進行json化然後給前端。不然的話瀏覽器會自動解析成文字的
})
前端需要進行接受二進制流
先引入proto.js文件以及protobufjs插件
import awesome from '../../proto/test_pb.js'
前端用axios請求/proto/get的路由,在回調函數裏的res.data爲後端的返回值。進行以下操作。打印出來的message3也是解析好的文件。
axios({
method:'get',
url: '/proto/get',
headers: { 'contentType':'application/x-protobuf'} }).then(res => {
let message3 = awesome.Test.deserializeBinary(res.data.data)
let nums = message3.getNum()
console.log(nums) // nums=42。解析出來就是後端傳過來的42
let pm = awesome.Test.deserializeBinary(res.data.data)
let protoBuf = pm.toObject()
console.log('protoBuf: ', protoBuf) // 打印出來是一個對象
}).catch((error) => {
console.log(error)
})
前端給後端傳數據
前端需要進行proto文件的賦值以及轉換爲二進制給後端
引入需要依賴的文件。
import awesome from '../../proto/test_pb.js'
import protobuf from 'protobufjs'
let message = new awesome.Test() // 調用Person對象 實例化
// 賦值
message.setNum(23)
message.setPayload('asd')
// 序列化
let bytes = message.serializeBinary() // 字節流
let blob = new Blob([bytes], {type: 'buffer'});
axios({
method:'post',
url: '/proto/send',
data: blob,
headers: {
'Content-Type': 'application/octet-stream' // 這裏根據後臺要求進行設置的,如果沒有要求應該是 application/octet-stream (二進制流)
}
}).then(res => {
console.log(res)
}).catch((error) => {
console.log(error)
})
後端需要接受文件
引入文件
let BufferHelper = require('bufferhelper');
接收字節流的代碼
app.post('/proto/send', function (req, res) {
let bufferHelper = new BufferHelper();
req.on("data", function (chunk) {
bufferHelper.concat(chunk);
});
req.on('end', function () {
let protobuf = require('protocol-buffers')
let buffer = bufferHelper.toBuffer();
console.log(buffer) // 這裏已經就是二進制文件了
let message3 = awesome.Test.deserializeBinary(buffer)
console.log(message3.getNum()) // 打印的就是前端傳的23
let pm = awesome.Test.deserializeBinary(buffer)
let protoBuf = pm.toObject()
console.log(protoBuf) // 打印的是{ num: 23, payload: 'asd', payloads: 'asds' }
console.log(protoBuf.num) // 打印23
});
})
以上就是關於protobuf的前後交互。如有錯誤,請指出。