原文: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中的不少常见问题。我推荐你们在本身的下一个项目中试试它。