原文:https://blog.envoyproxy.io/envoy-and-grpc-web-a-fresh-new-alternative-to-rest-6504ce7eb880
做者:Luc Perkins
譯者:李琪
gRPC-Web做爲gRPC的JavaScript客戶端庫,使Web應用能夠不用自定義HTTP服務器爲中介,直接經過Envoy與gRPC服務交互。通過了約兩年的活躍開發,上週(2018年10月底,譯者注)gRPC團隊在CNCF博客宣佈gRPC-Web的GA版本正式發佈。前端
自從在Improbable engineering blog讀到了這篇博文,我我的就對gRPC-Web很感興趣。以前一直很看好gRPC的性能、可拓展性和IDL(接口描述語言)驅動的服務交互方式,並且特別想在服務調用鏈中去掉REST部分。我很高興gRPC-Web發佈正式版本,它在 Web 開發領域開闢了新的方式。web
我以爲gRPC-Web的優點就是自Web端向下構建了完整的端到端gRPC服務架構。在之前,若是你想讓web端與gRPC服務交互,就必須本身開發REST接口處理HTTP和gRPC之間的轉換。而使用gRPC-Web,咱們再也不須要本身寫額外的HTTP接口,能夠直接用Protocol Buffers封裝全部數據接口(這裏借用了Envoy,在下文我會詳細解釋)。npm
下圖展現了基於gRPC服務架構構建Web App的兩種方式。左邊是傳統的REST方式。右邊是gRPC-Web方式。json
左圖所示,REST API只是做爲Web App和後端gRPC服務的鏈接點。在大部分場景下,REST 服務就是簡單的將HTTP調用轉換成gRPC調用。後端
舉個例子:客戶端須要驗證服務因而用POST
請求提交 JSON數據到HTTP服務器的/auth
。而後HTTP端把JSON數據轉換成Protobuf消息 AuthRequest
,並將消息發送給gRPC認證服務,最後從gRPC服務獲取到 AuthResponse
響應並將其轉換成JSON數據返回給前端。正如我在CNCF博客中文章中說的同樣,這種方法自己並無錯,它是一種解決方案,並且不少開發者都用的很好,若是它能知足你,你能夠繼續這樣用。api
更好的方案:若是能夠去掉HTTP中介咱們會少作不少工做(試想一下,JavaScript 端直接發送AuthRequest
消息給gRPC服務並得到 AuthResponse
響應)。這意味着咱們不須要關心HTTP狀態碼、JSON解析和HTTP服務自己帶來的部署和管理問題。安全
上圖右半部分是使用gRPC-Web的替代方案。它的架構更加清晰,一個protocol貫穿整個gRPC服務調用的始終。再也不有額外的HTTP邏輯,全部的數據接口都在 .proto
文件中定義。整個調用過程就是客戶端向gRPC服務發送Protobuf消息並從服務獲取Protobuf消息。服務器
咱們僅須要一個組件就能達到這種比較好的效果。架構
這裏必須認可,我以前講gRPC-Web直接調用gRPC服務的這種說法不是徹底正確的。使用gRPC-Web的客戶端調用仍然須要轉換成對於gRPC友好的調用。Envoy填補了這個角色。同時Envoy也是gRPC-Web內置的默認服務網關。cors
下圖中展現了Envoy結合gRPC-Web使用。圖中Web App調用了一個gRPC服務,該服務又依賴另外兩個gRPC服務。Envoy 將 HTTP/1.1 請求轉換成 HTTP/2 請求。底層其實仍是須要進行HTTP協議的轉換,但客戶端和服務端都不須要考慮HTTP層的問題。
gRPC-Web明顯優於REST,由於它只需開發者建立一個Envoy並作一些基礎配置,而不須要本身建立轉換層。
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 8080 }
filter_chains:
- filters:
- name: envoy.http_connection_manager
config:
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
prefix: "/」 route: cluster: auth_service cors: allow_origin: - "*"
allow_methods: GET, PUT, DELETE, POST, OPTIONS
allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web
max_age: "1728000"
expose_headers: grpc-status,grpc-message
enabled: true
http_filters:
- name: envoy.grpc_web
- name: envoy.cors
- name: envoy.router
clusters:
- name: auth_service
connect_timeout: 0.25s
type: logical_dns
http2_protocol_options: {}
lb_policy: round_robin
hosts:
socket_address:
address: auth-server
port_value: 9090複製代碼
總的來說它就是Envoy最基本的HTTP配置,只是有一點點區別:
一點 gRPC-Web 必須的自定義頭部:x-grpc-web
,grpc-status
和 grpc-message
(JavaScript 會自動處理它們)
內置的envoy.grpc_web
HTTP過濾器用來完成繁雜的gRPC-Web代理工做
在auth_service
配置中指定http2_protocol_options: {}
來獲取HTTP/2的連接
你只須要寫一點YAML配置就能夠從額外的HTTP適配工做中解脫出來。你不用關心HTTP與gRPC的方法映射問題,也不用去StackOverflow找HTTP的哪一個狀態碼對應gRPC的哪一個狀態碼,更不須要將Proto消息包裝成JSON。
gRPC-Web + Envoy爲web開發提供了一種全新的方式,它能保證Protocol Buffers和gRPC的類型安全還規避了HTTP+REST中的不少常見問題。我推薦你們在本身的下一個項目中試試它。