首先讓我們來看一個非常簡單的例子。 假設你想定義一個訊息格式,用來表示搜尋請求,其中每個搜尋請求都有三項:
- 一個查詢字串
- 你感興趣的特定結果頁
- 以及每個頁面的結果數
下邊是用來定義訊息型別的.proto
檔案
syntax = "proto3";
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}複製程式碼
- 第一行表示使用的protocol版本是3,如果你不寫這一條,
protobuf
會認為你使用的是protobuf2
,而且,這行必須是第一行,前邊也不能有註釋 SearchRequest
這條訊息定義了三個欄位(名稱/值對),每條訊息都要包含這三個欄位,每個欄位都有一個名稱和一個型別
欄位型別說明
在上面的例子中,所有欄位都是基本型別:兩個整數(page_number和result_per_page)和一個字串(query)。這些欄位也可以是複合型別,包括列舉和其他訊息型別
欄位標籤
訊息定義中的每個欄位都有唯一的編號標籤,這些標記用於以訊息二進位制格式標識欄位,訊息開始使用之後就不能修改
注意:
- 值在1到15範圍內的標籤需要一個位元組進行編碼,包括標識號和欄位型別
- 在16到2047範圍內的標籤佔用兩個位元組。
因此,你應該為非常頻繁出現的訊息元素保留標籤1到15。記住要為可能在將來新增的頻繁出現的元素留出一些空間。
最小的標籤是1,最大的標籤是536870911
,即2^29 - 1
,並且19000 - 19999
為protobuf
系統保留標籤,不能使用這幾個
欄位規則說明
一共有兩種型別
- singular: 一個符合規則的訊息應該具備零個或者一個該欄位
- repeated: 一個符合規則的訊息可以有零個或者任意個該欄位,並且保留重複的順序,在
proto3
中,基本型別的重複欄位預設壓縮編碼
新增更多訊息型別
可以在單個.proto
檔案中新增多個訊息型別,例如
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}
message SearchResponse {
...
}複製程式碼
新增註釋
可以使用//
為.proto
檔案新增註釋。例如
message SearchRequest {
string query = 1;
int32 page_number = 2; // Which page number do we want?
int32 result_per_page = 3; // Number of results to return per page.
}複製程式碼
保留欄位(欄位修改或者刪除解決辦法)
當訊息型別更新或者刪除時,這些被修改的欄位的標籤如果繼續使用,會造成資料不正確的問題,這時需要把這些標籤保留起來,防止跟舊版本的資料發生衝突。
(當使用JSON序列化時,欄位名稱也有可能存在這個問題),通俗來說,就相當於已經上線了使用A介面的一個APP,這個時候服務端如果想修改A介面的資料格式,只能新增一個介面,並且肯定不能使用A介面的地址
案例
message Foo {
reserved 2, 15, 9 to 11;
reserved "foo", "bar";
}複製程式碼
這就表示 2,15,9,10,11,"foo", "bar"都不能重複使用了
.proto
檔案會生成什麼?
當編譯.proto
檔案時,編譯器將根據你選擇的語言生成對應程式碼,你需要使用檔案中描述的訊息型別,包括獲取和設定欄位值,將訊息序列化 輸出流,以及解析來自輸入流的訊息
- 對於PHP,編譯器會為每個訊息生成一個類,用來描述該訊息
- 對於C ++,編譯器從每個
.proto
生成.h
和.cc
檔案,併為您的檔案中描述的每個訊息型別指定一個類 - 對於Java,編譯器會為每個訊息型別生成一個帶有類的
.java
檔案,以及用於建立訊息類例項的特殊Builder類 - Python有點不同, Python編譯器生成一個模組,其中包含
.proto
中每個訊息型別的靜態描述符,然後使用元類在執行時建立必要的Python資料訪問類 - 對於Go,編譯器會為檔案中的每種訊息型別生成一個具有型別的.pb.go檔案
- 對於Ruby,編譯器生成一個包含訊息型別的包含Ruby模組的.rb檔案
- 對於JavaNano,編譯器輸出與Java類似,但沒有Builder類
- 對於Objective-C,編譯器從每個
.proto
生成一個pbobjc.h
和pbobjc.m
檔案,在檔案中描述的每個訊息型別都有一個類 - 對於C#,編譯器從每個
.proto
生成一個.cs
檔案,在檔案中描述的每個訊息型別都有一個類