REST 的替代者:Envoy + gRPC-Web

原文: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

REST 方式

下圖展現了基於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消息。服務器

咱們僅須要一個組件就能達到這種比較好的效果。架構

Envoy 所扮演的角色

這裏必須認可,我以前講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並作一些基礎配置,而不須要本身建立轉換層。

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-webgrpc-statusgrpc-message (JavaScript 會自動處理它們)

  • 內置的envoy.grpc_webHTTP過濾器用來完成繁雜的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中的不少常見問題。我推薦你們在本身的下一個項目中試試它。

相關文章
相關標籤/搜索