Skip to content

Latest commit

 

History

History
174 lines (128 loc) · 7.21 KB

72.精读《REST, GraphQL, Webhooks, & gRPC 如何选型》.md

File metadata and controls

174 lines (128 loc) · 7.21 KB

72.精读《REST, GraphQL, Webhooks, & gRPC 如何选型》

项目联调阶段,约定接口的时候前后端就会坐在一起约定 http 接口,无非就是接口字段怎么传,数据格式应该怎么约定,入参是什么,出参返回数据类型是什么,怎么处理最好,对于传输方式,本文讨论的是联调前场景的选择。

REST

  • 使用的比较多的也是 Restful API 的形式进行接口设计了,他是无状态的,以资源为核心,对于操作资源约定了 URL 的带参方式,同时操作类型也是 HTTP Request 的方式,其基于 HTTP 原生接口,改造成本低,只需遵循约定的规范即可,降低了前后端耦合,利于快速迭代
curl -X GET 'https://www.baodu.com/product//list/shortList?uid=0

gRPC (wikipedia 摘录)

  • RPC 主要用于服务器之间的方法调用,影响性能的主要因素是序列化/反序列化,RPC 可打造一个高效率、低消耗的服务调用方式,适合 IOT 等对性能敏感的场景

  • gRPC 是谷歌推出的一个远程过程调用系统(Remote Procedure Call) ,基于 HTTP/2, 使用 Protocol Buffers 作为接口,其功能包括但不止于列出的部分:

    • 认证(Authentication)
    • 双向流(bidirectional streaming) 双工
    • 流控制(flow control)
    • 超时(timeouts)
  • 使用场景:微服务框架下不同语言的交互, 手机浏览器等设备直连后台, 高效客户端库

  • 这里主要涉及接口定义和服务器定义两块

      1. 定义接口

        // the greeting service definition
        service Greeter {
        	rpc SayHello (HelloRequest) return (HelloReply) {}
        	
        	rpc SayHelloAgain (HelloRequest) return (HelloReply) {}
        }
        
        message request message containing the user`s name.
        message HelloRequest {
        	string name = 1;
        }
        message HelloReply {
        string message = 1
        }
      1. 定义服务器
      function sayHello(call, callback) {
        callback(null, { message: "Hello" + call.request.name })
      }
      function sayHelloAgain(call, callback) {
        callback(null, { message: "Hello" + call.request.name })
      }
      function main() {
        var server = new grpc.Server();
        server.addProtoService(hello_proto.Greeter.service, {
          sayHello: sayHello,
          sayHelloAgain: sayHelloAgain
        });
        server.bind("0.0.0.0:50051", grpc.ServerCredentials,createInsecure());
        server.start()
      }
      1. 客户端接收
      function main() {
        var client = new hello_proto.Greeter(
        	"localhost:50051",
          grpc.credentials.createInsecure()
        );
        client.sayHello({ name: "you" }, function(err, response) {
          console.log("Greeting:", response.message)
        });
        client.sayHelloAgain({name: "you"}, function(err, response) {
          console.log("Greeting:", response.message)
        });
      }
    • 客户端和服务端都需要同时拿到 protobuf 结构,客户端数据发送也要依赖 proto 提供的方法,由框架内部做序列化/反序列化的工作

    • 有一些额外的手段也能将 grpc 转成 http,让网页也享受到高效低耗的好处,不过网页场景不会很在意节省几 kb 的流量

GraphQL

  • GraphQL 不是 REST 的替代品,是另一种交互形式,前端决定后端的返回结果

  • 能极大程度上精简请求响应的结果,想要什么数据由前端自己决定,不过前端能决定的数据也要后端能提供支持,后端接口可以一次性定义完所有接口,而不需要逐个开发。

  • 对比起来,GraphQL 只是前端决定返回结果的反模式,后端开发接口流程没有太多的变化。

  • GQL 的 API 可能看起来长这样:

    curl -v https://api.github.com/orgs/:orgs/members
  • 等价于 GQL query

    query {
      organization(login: github) {
        members(first: 100) {
          edges {
            node {
              name
              avatarUrl
            }
          }
        }
      }
    }
  • 返回字段

    {
      "data": {
        "organization": {
          "members": {
            "edges": [
              {
                "node": {
                  "name": "Chris Wanstrath",
                  "avatarUrl": "https://avatars0.githubusercontent.com/u/2?v=4"
                }
              },
              {
                "node": {
                  "name": "Justin Palmer",
                  "avatarUrl": "https://avatars3.githubusercontent.com/u/25?v=4"
                }
              }
            ]
          }
        }
      }
    }
  • 这里需要系统帮你做出映射的 query 查询,Apollo-client 刚好可以提供此功能

webHooks

  • webhooks 完全依赖服务端主动推送,前端不主动发送请求
  • 比较适合解决轮询问题,轮询其实就是一个妥协的行为,后端不支持 webhooks 模式只能依靠轮询模仿

使用场景

  1. REST: 无状态数据传输结构,适用通用、快速迭代和标准化语义场景。
  2. gRpc: 轻量传输方式,适合对性能要求较高或者环境苛刻情景,IOT 等
  3. GraphQL: 请求自己定义数据返回格式,减少前后端联调成本
  4. webhooks: 服务端主动推送,适合轮询场景

精读

  • REST 不一定适用所有场景,其实像我们自己的团队,都不遵守 RESTFUl 开发方式,通常接口不做不到语义化,GET 和 SET 为主,不过接口如果要提供给第三方使用,就得好好约定接口规范语义,内部 TOB 产品,性能和冗余都比较少考虑,所以效率就是第一位,接口约定很可能是业务形态决定的,而不是凭空对技术对比得出。
  • gRPC 是服务端交互的首选,像前端同学 node 开发的时候,喜欢用 Http 方式做服务器质检的通讯,可能比较疑惑为什么内部 Java 应用都不提供 Http 方式调用,而是另外的名字,了解 grpc 之后,会认识到这些平台都是对 RPC 的封装,服务间通信对性能和延时要求很高,所以适合专门为性能优化的 gRPC 服务
  • GQL 需要配套使用,其不是 REST 的替代品,不要想着团队从 HTTP 接口迁移到 GQL 效率就会有 X%的提高,GQL 的方案是一种新的前后端交互约定,上手成本比较高, 同时为了方便前端同学拼接参数,等于把后端的工作量叫一部分给前端,所以如果没有一个比较好的平台查阅、维护、生成这些接口的定义,反而开发效率会下降,GQL 比较适合像美团这种大型企业有专门的团队去做基建。
  • WebHooks 对于三方鉴权登录等等没有前端界面做中转的场景,或者强安全要求的支付场景,适合 Webhooks 做数据主动推送,前端不需要参与,一句话就是前端不安全,他也不是 REST 的替代品,只是一种新的前后端交互方式。对于慢查询的场景,前端轮询可以实现,反而 WebSocket 体验更佳,无状态的特性反而会降低服务器负担,所以慢查询和即时通讯要区分对待,用户对消息及时性敏感程度决定使用方案。内部对于 B 端项目版本更新的推送就使用了轮询的方案,因为版本变动的频率不高,但是也会存在变化,需要通知客户端更新。