protobuf 是傳輸數據序列化的一個通用規則,相比xml和json更快更小。
本次使用的是proto3,3相比於2有一些特性上的不同,例如3默認了optional聲明。
所有字段都是可選賦值,這樣做是爲了兼容有些字段會在特定版本被廢棄,序列化時,沒有的字段不會被轉化。
caretor js 使用
編寫好proto文件,就可以使用protoc進行編譯了,creatorjs引用google-protobuf.js的時候會有問題,解決無果以後我決定使用protobufjs,使用protobufjs最好有npm環境來下載安裝,nodejs和npm的安裝這裏就不多介紹了。
- 安裝protobufjs
-g 是全局安裝,安裝完以後,找到目錄,配置好…/protobufjs/bin 環境變量,bin目錄下有兩個可執行文件 pbjs和pbts,是用來編譯proto文件的。使用protobufjs就不會用到protoc。
# npm install -g protobufjs
- 編譯proto文件
// game.proto
syntax = "proto3"
message Login {
string username = 1;
string password = 2;
int32 uid = 3;
}
message LoginResult {
string token = 1;
}
配置好環境變量,就使用pbjs編譯proto文件
# pbjs -t json-module game.proto > client.json
# pbjs -t static-module game.proto > clientProto.js
-t [params] | 參數說明 |
---|---|
json | JSON representation |
json-module | JSON representation as a module |
proto2 | Protocol Buffers, Version 2 |
proto3 | Protocol Buffers, Version 3 |
static | Static code without reflection (non-functional on its own) |
static-module | Static code without reflection as a module |
注意:不同參數導出的的文件類型不一樣。
- js中使用
// proto.js
const proto = require("clientProto")
module.exports = {
// static-module
proto: function(name, pwd) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readystatus = 4 && xhr.status >= 200 && xhr.status < 300) {
var b = stringToBytes(xhr.responseText); //這裏需要將字符串轉爲byte數組
proto.LoginResult.decode(b);
}
}
xhr.open("POST", "localhost:8080/login");
m_xhr.setRequestHeader("Content-Type","application/x-protobuf");
m_xhr.setRequestHeader("Accept","application/x-protobuf");
if (m_xhr.overrideMimeType){
//這個是必須的,否則返回的是字符串,導致protobuf解碼錯誤
//具體見http://www.ruanyifeng.com/blog/2012/09/xmlhttprequest_level_2.html
m_xhr.overrideMimeType("text/plain; charset=x-user-defined");
}
var param = proto.Login.encode({username:name, password:pwd).finish();
xhr.send(param);
},
// json-module, json文件沒使用,用過後補全
proto2: function() {
}
};
golang 使用
go使用的話,我用的是iris框架,這裏就舉例iris怎麼解析。
package main
import (
"gameProto"
"github.com/golang/protobuf/proto"
"github.com/kataras/iris"
)
func main() {
app := iris.New()
app.Post("/login", loginHandler)
app.Run(iris.Addr("0.0.0.0:8080"))
}
func ProtoUnmashal(data []byte, v interface{}) error {
return proto.Unmashal(data, v.(proto.Message)) // proto解析方法
}
func loginHandler(c iris.Context) {
login := &gameProto.Login{} // 這個是解析後go結構
// 解析客戶端傳的參數
if c.UnmarshalBody(login, iris.UnmarshalerFunc(ProtoUnmashal)); err != nil {
return
}
// do something ...
loginResult := &gameProto.LoginResult{}
loginResult.Token = "zx7g9f8h79j80sh98af766"
if b, err := proto.Mashal(loginResult); err != nil {
return
} else {
c.Write(b)
}
}