前言:
gRPC-Web是一個JavaScript客戶端庫,可以使Web應用程序直接與后端gRPC服務進行通信,而無需HTTP服務器充當中介。
這意味着可以通過使用.proto文件定義客戶端和服務器端數據類型和服務接口,輕松構建真正的端到端gRPC應用程序體系結構。因此,gRPC-Web為Web開發的整個REST范例提供了一種引人注目的新替代方案。
基礎:
gRPC-Web能夠使用.protodefinitions和自動生成客戶端JavaScript在客戶端Web應用程序和后端gRPC服務器之間定義服務“契約”(可以在Closure編譯器JavaScript或更廣泛使用的CommonJS之間進行選擇)。
可以放棄開發過程:創建自定義JSON序列化和反序列化邏輯,處理HTTP狀態代碼(可能因REST API而異),內容類型協商等。從更廣泛的架構角度來看,gRPC-Web使端到端gRPC成為可能。下圖說明了這一點:
在左側的gRPC-Web Universe中,客戶端應用程序向GRPC后端服務器說出協議緩沖區,該服務器向其他gRPC后端服務說出協議緩沖區。
在右側的REST Universe中,Web應用程序將HTTP發送到后端REST API服務器,然后該服務器將協議緩沖區稱為后端服務。需要明確的是,REST應用程序本身沒有任何問題。
使用REST API服務器構建了大量非常成功的應用程序,這些服務器使用非HTTP協議與后端服務進行通信。但是想象一下,這些應用程序的開發過程圍繞着一個協議和一組.proto接口(以及一組服務契約),幾乎可以感受到無數小時的節省和頭痛的避免。
gRPC-Web的好處不僅僅是“技術”;他們也是組織的。明亮的橙色線不僅僅是一個不同的協議 - 它是一個獨立的工作和認知負荷來源,現在可以很容易地變成亮綠色。
使用gRPC-Web的優點:
隨着時間的推移,gRPC-Web將提供更廣泛的功能集。但可以看到它從一開始就提供了一些重大勝利:端到端gRPC - 如上所述,使用gRPC-Web,可以正式從堆棧中刪除REST組件並將其替換為純gRPC,能夠使用Protocol Buffers創建整個RPC管道。想象一下客戶端請求轉到HTTP服務器的情況,然后HTTP服務器與5個后端gRPC服務進行交互。將花費盡可能多的時間來構建HTTP交互層,因為將構建整個管道的其余部分。前端和后端團隊之間更緊密的協調 - 回想上面的圖表。使用Protocol Buffers定義整個RPC管道,不再需要將“微服務團隊”與“客戶團隊”一起使用。客戶端 - 后端交互只是一個gRPC層。老實說,還沒有完全掌握端到端測試,服務網格集成,持續集成/交付等方面的影響。輕松生成客戶端庫 - 使用gRPC-Web,與“外部”世界交互的服務器,即連接后端堆棧和互聯網的隔膜,現在是gRPC服務器而不是HTTP服務器,這意味着所有服務都是客戶端庫可以是gRPC庫。需要Ruby,Python,Java和其他4種語言的客戶端庫嗎?不再需要為所有這些客戶端編寫HTTP客戶端。
一個gRPC-Web示例:
一個簡單的TODO應用程序。在gRPC-Web中,可以從一個簡單的todos.proto定義開始,如下所示:
syntax = “proto3”; package todos; message Todo { string content = 1; bool finished = 2; } message GetTodoRequest { int32 id = 1; } service TodoService { rpc GetTodoById (GetTodoRequest) returns (Todo); }
Tip: 可以在GitHub看rawtodos.proto
可以使用該.proto定義使用protoc命令行工具生成CommonJS客戶端代碼:
protoc echo.proto \ --js_out=import_style=commonjs:./output \ --grpc-web_out=import_style=commonjs:./output
Tip: 可以在GitHub看rawprotoc-gen.sh
現在從后端gRPC服務器獲取TODO列表可以這么簡單:
const {GetTodoRequest} = require(‘./todos_pb.js’); const {TodoServiceClient} = require(‘./todos_grpc_web_pb.js’); const todoService = new proto.todos.TodoServiceClient(‘http://localhost:8080’); const todoId = 1234; var getTodoRequest = new proto.todos.GetTodoRequest(); getTodoRequest.setId(todoId); var metadata = {}; var getTodo = todoService.getTodoById(getTodoRequest, metadata, (err, response) => { if (err) { console.log(err); } else { const todo = response.todo(); if (todo == null) { console.log(`A TODO with the ID ${todoId} wasn’t found`); } else { console.log(`Fetched TODO with ID ${todoId}: ${todo.content()}`); } } });
Tip: 可以在GitHub托管的rawtodo-service.js
同樣,沒有HTTP代碼或方法,沒有JSON解析,沒有頭協商。聲明了數據類型和服務接口,並且gRPC-Web摘錄了所有“硬接線”樣板,提供了一個干凈且人性化的API(基本上與當前用於gRPC API的Node.js相同的API,剛剛轉移到客戶端)。在后端,gRPC服務器可以用任何支持gRPC的語言編寫,包括Go,Java,C ++,Ruby,Node.js等等(請參閱官方gRPC文檔中的語言特定文檔)。最后一塊拼圖是服務代理。從一開始,gRPC-Web將支持Envoy作為默認服務代理,它具有內置的envoy.grpc_web過濾器,只需幾行復制和配置即可應用。
下一步
gRPC-Web正式發布版本意味着核心構建塊已牢固到位,可以在生產Web應用程序中使用。但是gRPC-Web還有很多其他的東西要來。查看官方路線圖,了解核心團隊在不久的將來所設想的內容。gRPC-Web還存在着一些問題:
1、前端框架集成 - 常用的前端框架如React,Angular和Vue尚未提供對gRPC-Web的官方支持。希望看到這些框架能夠支持它,因為每個框架都會從gRPC中受益匪淺。特定於語言的代理支持 - 從GA版本開始,Envoy是gRPC-Web的默認代理,通過特殊模塊提供支持。但也很樂意看到特定語言的進程內代理的開發。進程內代理消除了對特殊代理(例如Envoy和nginx)的需求,並且使得使用gRPC-Web變得更加容易。
2、特定於語言的代理支持 - 從GA版本開始,Envoy是gRPC-Web的默認代理,通過特殊模塊提供支持。也很樂意看到特定語言的進程內代理的開發。進程內代理消除了對特殊代理(例如Envoy和nginx)的需求,並且使得使用gRPC-Web變得更加容易。
結語
相信gRPC-Web的話題在社區隨着時間推移,會越來越活躍。