Cloud Endpoints 支援通訊協定轉碼,讓用戶端可使用 HTTP/JSON 存取您的 gRPC API。可擴充服務 Proxy (ESP) 能將 HTTP/JSON 轉碼為 gRPC。
本指南說明:
- 如何在您的
.proto
檔案中使用註解,指定從 HTTP/JSON 到 gRPC 的資料轉換 - 如何在 Endpoints 中部署您的服務以使用此功能
- 哪裡可以找到有關設計和實作 gRPC 服務轉碼的更多參考資訊
本指南假設您已完成 gRPC 教學課程,且熟悉 gRPC 專用的 Endpoints API 基本概念。
設計容易轉碼的 API
轉碼包含將 HTTP/JSON 要求及其參數對應至 gRPC 方法,以及「這些方法的」參數和傳回類型。因此,雖然您可以將 HTTP/JSON 要求對應至任何任意 API 方法,但如果 gRPC API 的結構設計是以資源為導向 (就像傳統 HTTP REST API),就有助於進行此作業。換句話說,您設計 API 服務,讓服務使用少量與 HTTP 動詞 (例如 GET
和 PUT
) 相對應的標準方法,在服務的資源和資源集合上運作 (它們本身就是一種資源類型)。這些標準方法為 List
、Get
、Create
、Update
和 Delete
。
如有必要,API 也可以有一些非標準的自訂方法,雖然這些方法不是很容易對應。
如要進一步瞭解資源導向設計和標準轉碼對應,請參閱 API 設計指南。設計指南是 Google 在設計 Cloud API 等公用 API 時所遵循的設計標準。雖然您不需要遵循此指南使用 gRPC 轉碼,仍強烈建議您這麼做。尤其是以下頁面可協助您瞭解這些設計原則,以及如何將有用的轉碼對應功能新增至您的方法:
以下參考頁面可能也很有用:
- Http 規則參考:HTTP 對應規則的詳盡參考資料。
在本文件的其餘內容中,您將使用在教學課程中所使用的 Bookstore 範例,該範例已使用這些原則。Bookstore 有「書籍」資源的「書架」集合,可讓使用者 List
、Get
、Create
或 Delete
。
哪裡可以設定轉碼功能
gRPC 轉碼功能預設為啟用,無需進行任何設定即可開始使用。請按照部署使用轉碼功能的服務的操作說明進行。之後,當您使用方法的要求訊息欄位值 (如果有的話) 做為 HTTP 要求主體中的 JSON,來將 HTTP POST
要求傳送至網址路徑 GRPC_SERVICE_FULL_NAME/METHOD_NAME>
,ESP 會將要求訊息傳送至適當的 gRPC 方法。在上述範例中,GRPC_SERVICE_FULL_NAME
是 gRPC 服務的完整名稱,而 METHOD_NAME
是方法的名稱。
例如,如果您將 POST
傳送至 Bookstore 的 ListShelves
網址,如下所示:
curl -XPOST http://mydomain/endpoints.examples.bookstore.Bookstore/ListShelves
您會收到 JSON 格式的目前書架清單。
但是,就 HTTP 介面設計而言,我們強烈建議您如本文件的其餘部分中所述,明確地設定對應。
服務設定的 gRPC API 設定標準可讓您確切地指定資料應如何從 HTTP/JSON 轉譯至 gRPC。有兩種支援此操作的機制:在 .proto
檔案中直接註解,以及在 YAML 中直接註解 (做為 gRPC API 設定檔的一部分)。我們建議您使用 proto
註解以便讀取和維護。如要進一步瞭解 YAML 設定且可能需要使用這項功能,請參閱在 YAML 檔案中設定轉碼功能一節。
以下是從 Bookstore 使用建議方法的範例:
// Returns a specific bookstore shelf.
rpc GetShelf(GetShelfRequest) returns (Shelf) {
// Client example - returns the first shelf:
// curl http://DOMAIN_NAME/v1/shelves/1
option (google.api.http) = { get: "/v1/shelves/{shelf}" };
}
...
// Request message for GetShelf method.
message GetShelfRequest {
// The ID of the shelf resource to retrieve.
int64 shelf = 1;
}
註解會向 ESP 告知使用 http://mydomain/v1/shelves/1
網址提出 HTTP GET
要求會呼叫 gRPC 伺服器的 GetShelf()
方法,而 GetShelfRequest
包含要求的書架 ID shelf
(在這個案例中為 1
)。
新增轉碼對應功能
本節說明 Bookstore 範例中的一些其他對應註解。Bookstore 範例中有兩個 proto
檔案範例,以便使用或不使用轉碼對應功能進行部署,以及比較 proto
檔案中的差異:
bookstore.proto
:用於 Endpoints 教學課程且沒有轉碼對應。http_bookstore.proto
:已新增轉碼繫結。
要對如何指定轉碼對應有更全面的瞭解,請參閱標準方法、自訂方法和 HTTP 規則參考資料。
對應 List
方法
.proto
檔案中有 List
方法的定義及其回應類型:
// Returns a list of all shelves in the bookstore. rpc ListShelves(google.protobuf.Empty) returns (ListShelvesResponse) { // Define HTTP mapping. // Client example (Assuming your service is hosted at the given 'DOMAIN_NAME'): // curl http://DOMAIN_NAME/v1/shelves option (google.api.http) = { get: "/v1/shelves" }; } ... message ListShelvesResponse { // Shelves in the bookstore. repeated Shelf shelves = 1; }
以粗體顯示的註解指定了此方法的 HTTP 對應。
option (google.api.http)
指定這個方法是 gRPC HTTP 對應註解。get
指定這個方法已對應至 HTTPGET
要求。"/v1/shelves"
是GET
要求用來呼叫這個方法的網址路徑範本 (已附加至服務的網域)。網址路徑也稱為資源路徑,因為它通常會指定您要使用的「物體」或資源。在這個案例中為 Bookstore 的所有書架資源。
舉例來說,如果用戶端將 GET
傳送至 http://mydomain/v1/shelves
網址以呼叫這個方法,ESP 就會呼叫 gRPC 方法ListShelves()
。然後 gRPC 後端會傳回書架,而 ESP 則會將其轉換為 JSON 格式並傳回用戶端。
對應 Get
方法
.proto
檔案中定義了 Bookstore 的 GetShelf
方法及其要求和回應類型:
// Returns a specific bookstore shelf. rpc GetShelf(GetShelfRequest) returns (Shelf) { // Client example - returns the first shelf: // curl http://DOMAIN_NAME/v1/shelves/1 option (google.api.http) = { get: "/v1/shelves/{shelf}" }; } ... // Request message for GetShelf method. message GetShelfRequest { // The ID of the shelf resource to retrieve. int64 shelf = 1; } ... // A shelf resource. message Shelf { // A unique shelf id. int64 id = 1; // A theme of the shelf (fiction, poetry, etc). string theme = 2; }
以粗體顯示的註解指定了此方法的 HTTP 對應。
option (google.api.http)
指定這個方法是 gRPC HTTP 對應註解。get
指定這個方法已對應至 HTTPGET
要求。- 如前所述,
"/v1/shelves/{shelf}"
是要求的網址路徑,但它指定了/v1/shelves/
和{shelf}
。這個大括號標記法會告知 ESP 位於{shelf}
中的任何內容,就是它應在方法的GetShelfRequest
參數中提供給shelf
的值。
如果用戶端透過傳送 GET
至網址 http://mydomain/v1/shelves/4
來呼叫此方法,ESP 會以 shelf
值 4
來建立 GetShelfRequest
,然後使用它來呼叫 gRPC 方法 GetShelf()
。接著 gRPC 後端會以 ID 4
傳回要求的 Shelf
,然後 ESP 會將其轉換為 JSON 格式並傳回用戶端。
使用這個方法時,shelf
用戶端只需要提供單一要求欄位值,即您在網址路徑範本中使用大括號「擷取」標記法指定的值。如有必要,您也可以擷取網址的多個部分以識別要求的資源。例如,GetBook
方法需要用戶端在網址中同時指定書架 ID 和書籍 ID:
// Returns a specific book.
rpc GetBook(GetBookRequest) returns (Book) {
// Client example - get the first book from the second shelf:
// curl http://DOMAIN_NAME/v1/shelves/2/books/1
option (google.api.http) = { get: "/v1/shelves/{shelf}/books/{book}" };
}
...
// Request message for GetBook method.
message GetBookRequest {
// The ID of the shelf from which to retrieve a book.
int64 shelf = 1;
// The ID of the book to retrieve.
int64 book = 2;
}
除了欄位值的文字和擷取大括號以外,網址路徑範本還可以使用萬用字元,來表示網址這部分中的任何內容都應擷取。上述範例使用的 {shelf}
標記法其實是 {shelf=*}
的捷徑。您可在 HTTP 規則參考一文中進一步瞭解路徑範本的規則。
此方法類型沒有指定的 HTTP 要求內容:如要進一步瞭解如何對應 Get
方法 (包括使用查詢參數),請參閱標準方法一文。
對應 Create
方法
Bookstore 的 CreateShelf
方法會對應至 HTTP POST
。
// Creates a new shelf in the bookstore. rpc CreateShelf(CreateShelfRequest) returns (Shelf) { // Client example: // curl -d '{"theme":"Music"}' http://DOMAIN_NAME/v1/shelves option (google.api.http) = { post: "/v1/shelves" body: "shelf" }; } ... // Request message for CreateShelf method. message CreateShelfRequest { // The shelf resource to create. Shelf shelf = 1; } ... // A shelf resource. message Shelf { // A unique shelf id. int64 id = 1; // A theme of the shelf (fiction, poetry, etc). string theme = 2; }
option (google.api.http)
指定這個方法是 gRPC HTTP 對應註解。post
指定這個方法已對應至 HTTPPOST
要求。- 如同之前一樣,
"/v1/shelves"
是要求的網址路徑。 - HTTP 要求主體中會使用
body: "shelf"
,以 JSON 格式指定您要新增的資源。
因此,如果用戶端像這樣呼叫此方法:
curl -d '{"theme":"Music"}' http://DOMAIN_NAME/v1/shelves
ESP 會使用 JSON 主體建立具有 CreateShelfRequest
適用的 "Music"
主題的 Shelf
值,然後呼叫 gRPC CreateShelf()
方法。請注意,用戶端「不會」為 Shelf
提供 id
值。建立新書架時,服務會提供 Bookstore 的書架 ID。
您在 API 說明文件中提供這種類型的資訊給服務的使用者。
在內容中使用萬用字元
您可以在主體對應中使用特殊名稱 *
,將每個未與路徑範本繫結的欄位定義為應該對應至要求主體。如此一來,即會啟用下列 CreateShelf
方法的替代定義。
// Creates a new shelf in the bookstore. rpc CreateShelf(CreateShelfRequest) returns (Shelf) { // Client example: // curl -d '{"shelf_theme":"Music", "shelf_size": 20}' http://DOMAIN_NAME/v1/shelves/123 option (google.api.http) = { post: "/v1/shelves/{shelf_id}" body: "*" }; } ... // Request message for CreateShelf method. message CreateShelfRequest { // A unique shelf id. int64 shelf_id = 1; // A theme of the shelf (fiction, poetry, etc). string shelf_theme = 2; // The size of the shelf int64 shelf_size = 3; }
option (google.api.http)
指定這個方法是 gRPC HTTP 對應註解。post
指定這個方法已對應至 HTTPPOST
要求。"/v1/shelves/{shelf_id}"
是要求的網址路徑。{shelf_id}
中的任何內容都是CreateShelfRequest
中shelf_id
欄位的值。- 在本例中,
body: "*"
會用於 HTTP 要求主體,指定shelf_id
以外的所有要求欄位,包括shelf_theme
和shelf_size
。如果 JSON 主體中含有這兩個名稱的任何欄位,其值會用於CreateShelfRequest
的對應欄位。
舉例來說,如果用戶端像這樣呼叫此方法:
curl -d '{"shelf_theme":"Music", "shelf_size": 20}' http://DOMAIN_NAME/v1/shelves/123
ESP 會使用 JSON 主體和路徑範本建立 CreateShelfRequest{shelf_id: 123 shelf_theme: "Music" shelf_size: 20}
,然後使用該 CreateShelfRequest{shelf_id: 123 shelf_theme: "Music" shelf_size: 20}
呼叫 gRPC CreateShelf()
方法。詳情請參閱 HttpRule。
在 YAML 檔案中設定轉碼功能
另一種方法是您在 gRPC API 設定 YAML 檔案 (而不是 .proto
檔案) 中指定 HTTP 至 gRPC 對應。如果您有用於多個服務的單一 proto
API 定義,並為每個服務指定不同的對應,您可能需要在 YAML 檔案中設定轉碼。
YAML 檔案的 http
區段中的 rules
指定如何將 HTTP/JSON 要求對應至 gRPC 方法:
http:
rules:
...
#
# 'GetShelf' is available via the GET HTTP verb and '/shelves/{shelf}' URL
# path, where {shelf} is the value of the 'shelf' field of 'GetShelfRequest'
# protobuf message.
#
# Client example - returns the first shelf:
# curl http://DOMAIN_NAME/v1/shelves/1
#
- selector: endpoints.examples.bookstore.Bookstore.GetShelf
get: /v1/shelves/{shelf}
...
api_config_http.yaml
中有更完整的範例,說明如何將這個方法用於 Bookstore 服務範例。
部署使用轉碼的服務
部署使用轉碼功能的 gRPC 服務與部署任何其他 gRPC 服務大致相同,但有一個主要區別。在教學課程中,範例需要接受來自用戶端範例的 gRPC 要求。不過,如果您也想要讓 Bookstore 接受 HTTP 要求,則須針對 ESP 執行一些額外的設定。用戶端使用 HTTP1.1
通訊協定將 JSON/HTTP 要求傳送至 ESP,因此 ESP 必須設定為使用 SSL (SSL 通訊埠可同時支援兩種要求類型),或必須啟用特殊通訊埠才能接受這些呼叫。剩下的部署作業與您所選環境的教學課程大致相同。
確保已部署 HTTP 規則
如果您已下載 Bookstore 範例以進行我們的教學課程,請注意,您必須下載稍微不同版本的 .proto
檔案,且該版本中包含註解:http_bookstore.proto
。執行 protoc
之前,您也需要從 GitHub 複製 googleapis
存放區,因為您在包含的路徑中需要有 annotations.proto
。
git clone https://github.com/googleapis/googleapis
GOOGLEAPIS_DIR=<your-local-googleapis-folder>
接著,將設定部署至 Endpoints 時,您需要從 http_bookstore.proto
建立新的 .pb
描述元:
protoc \
--include_imports \
--include_source_info \
--proto_path=${GOOGLEAPIS_DIR} \
--proto_path=. \
--descriptor_set_out=api_descriptor.pb \
http_bookstore.proto
如果您使用替代方法在 gRPC API 設定 YAML 檔案中設定 HTTP 對應,則還得確保您在將設定部署至 Endpoints 前已先部署相關規則。如要使用 Bookstore 服務嘗試此操作,其基本規則位於 api_config.yaml
檔案中,HTTP 規則則位於 api_config_http.yaml
檔案中:
gcloud endpoints services deploy api_descriptor.pb api_config.yaml api_config_http.yaml
使用 SSL
如果您在用戶端和 ESP 之間的通訊啟用了安全資料傳輸層 (SSL),用戶端即可以使用同一個通訊埠來進行 gRPC 或 HTTP1.1
呼叫。要瞭解如何為 Endpoints 服務設定 SSL,請參閱啟用 SSL 相關頁面。
在 Google Kubernetes Engine 設定檔 (GKE) 中使用 --ssl_port
參數或使用 docker run
指令 (Compute Engine/Docker),指定通訊埠讓 ESP 能夠接受 SSL 呼叫。
args: [
"--http_port", "8080",
"--ssl_port", "443", # enable SSL port at 443 to serve https requests
"--backend", "grpc://127.0.0.1:8081", # gRPC backend.
"--service", "SERVICE_NAME",
"--rollout_strategy", "managed",
]
設定 HTTP1.1
通訊埠
如果您不是使用 SSL,則須為 HTTP1.1
要求設定個別的通訊埠,因為 gRPC 和 HTTP1.1
無法在沒有 SSL 的情況下共用相同的通訊埠。在 GKE 設定檔中使用 --http_port
參數或使用 docker run
指令,指定要接受 HTTP1.1
呼叫的通訊埠。如果您也想要讓 ESP 接受 gRPC 呼叫,則也需要使用 --http2_port
參數來指定 gRPC 通訊埠。
args: [
"--http_port", "8080", # for HTTP 1.1
"--http2_port", "8090", # for gRPC
"--backend", "grpc://127.0.0.1:8081", # gRPC backend.
"--service", "SERVICE_NAME",
"--rollout_strategy", "managed",
]
使用轉碼功能呼叫服務
本節將說明服務設定以及如何對服務執行 HTTP 呼叫。
服務設定
本節假設您已針對您選擇的環境完成基本 gRPC 服務教學課程,且有 GKE 叢集或 Compute Engine 執行個體來執行範例。
- 首先,如上方確保已部署 HTTP 規則一節中所述,確保您已將支援 HTTP 的 Bookstore 服務設定部署至 Endpoints。
依照所選平台的教學課程所說明的操作步驟來部署後端和 ESP,並使用
--http_port
參數為HTTP1.1
要求啟用通訊埠:- GKE 部署:按照將範例 API 和 ESP 部署至叢集一文中的操作說明,確定 GKE 設定檔中已指定
"--http_port"
參數。 - Compute Engine 部署:按照在 Docker 容器中執行範例 API 和 ESP 一文的操作說明進行。
執行預先封裝的 ESP Docker 容器時,請確認
docker run
指令中已指定--http_port
參數。
- GKE 部署:按照將範例 API 和 ESP 部署至叢集一文中的操作說明,確定 GKE 設定檔中已指定
對服務進行 HTTP 呼叫
- 取得 ESP 的外部 IP 位址,並將其設定為
$ESP_IP
。 使用
curl
發出以下 HTTP 要求curl http://$ESP_IP/v1/shelves
(如果您使用的是安全資料傳輸層 (SSL),則使用與
https://
相同的網址)。伺服器會回應:{"shelves":[{"id":"1","theme":"Fiction"},{"id":"2","theme":"Fantasy"}]}
如果輸出顯示二進位的回應,請檢查您的通訊埠設定,因為您可能正在使用 HTTP2 通訊埠,而非 HTTP 通訊埠。
試用
Create
方法。CreateShelf
需要 API 金鑰,因此您需要為專案建立金鑰,並將其設為$KEY
。現在,請呼叫:curl -d '{"theme":"Music"}' http://$ESP_IP/v1/shelves?key=$KEY
如果您再次呼叫
GetShelves
,應該會看到新的書架。