# 相关概念

# REST

  • HTTP 协议定义了多种 HTTP 方法,优点是自由度较大,缺点是用法容易混乱。
    • 例如,执行某个操作时,有的开发人员偏好使用 GET 方法,有的开发人员偏好使用 POST 方法。
    • 因此,一些开发人员约束了 HTTP 协议的用法,制定了一套更简单的 API 规范,称为表述性状态转移(Representational State Transfer,REST)。
    • 符合 REST 规范的 HTTP API 称为 RESTful API 。
  • 主要规范:
    • 调用 API 操作一个对象时,给该对象分配一个唯一的 URL 标识。
    • URL 应该是名词性的,且区分单复数。比如 /students/names 优于 /students/getName
    • 尽量只使用 GET、POST、PUT、DELETE 四种 HTTP 方法,实现 CRUD 操作。
    • 报文 body 通常采用 JSON 格式。
    • 客户端与服务器之间采用无状态通信,所以客户端的每个请求都应该自带上下文信息。
  • 优点:
    • 简单易懂。
  • 缺点:
    • API 的操作对象,可能不适合用 URL 表示。
    • 只使用几种基础的 HTTP 方法,不能体现某些特殊操作,比如既需要读、又需要写的操作。

# RPC

:远程过程调用(Remote Procedure Call),是一种进程间的网络通信技术。

  • 用途:在本机某个进程的代码中,通过 RPC API ,调用其它主机上某个进程的代码。
  • RPC 与 REST 的区别:
    • REST 强调的是 API 的用法,必须遵守 REST 规范。而 RPC 强调的是 API 的用途,能实现远程过程调用。
    • RESTful API 必须基于 HTTP 协议进行网络通信。而 RPC API 可以基于 TCP、UDP、HTTP 等通信协议。
  • 例如 gRPC 是一个 RPC 分布式系统框架,基于 HTTP/2 协议,由 Google 公司发布。

# GraphQL

:一种查询语言,方便通过 API 查询图状数据。

  • 2015 年,由 Facebook 公司发布。
  • 用于 HTTP API 时,可视作 REST 的替代方案。
  • 例:
    1. 客户端发出查询请求:
      {
        human(id: "2") {  # 查询指定 id 的 human 对象,要求返回指定字段的值
          name
          age
        }
      }
      
    2. 服务器返回响应:
      {
        "human": {
          "name": "Leo",
          "age": 20
        }
      }
      

# SSE

:全称为 Server-Sent Events ,是 2004 年发明的一项 HTTP 流式通信技术,主流浏览器都支持该功能。

  • 工作流程:
    1. 客户端发送一个 HTTP 请求报文。
    2. 服务器返回一个 HTTP 响应报文,带有 content-type: text/event-stream 头部,表示 body 数据会分成多段传输。
      • 规定每段数据以 data: 开头,以 \n\n 结尾。
      • 双方保持当前 HTTP 通信所建立的 TCP 连接,直到传输了最后一段 body 数据。
      • TCP 连接可能突然断掉。重新建立 TCP 连接时,需要知道 body 数据的传输进度。因此,建议每段数据包含 id: <int> 字段,取值递增。
  • 例:用 Python 开发一个 HTTP 服务器,提供 SSE 接口
    from flask import Flask, Response
    import time
    
    app = Flask(__name__)
    
    @app.route('/sse')
    def sse():
        def iter_events():
            for i in range(10):
                data = 'hello'
                yield f'data: {data}\nid: {i}\n\n'
                time.sleep(1)
        return Response(iter_events(), mimetype='text/event-stream')
    
    if __name__ == "__main__":
        app.run(debug=True)
    

# WebSocket

:HTML5 标准定义的一个网络通信协议。

  • 属于应用层协议,基于 TCP 协议进行通信。
  • 通信双方不能直接进行 WebSocket 通信,需要先通过 HTTP 通信进行握手,流程如下:
    1. 客户端发送一个 GET 请求,采用 HTTP/1.1 协议,请求头包含 Upgrade: websocketConnection: Upgrade ,表示请求从 HTTP 协议切换到 WebSocket 协议。
    2. 服务器如果同意切换,则返回一个响应报文,状态码为 101 (Switching Protocol) 。
    3. 双方保持当前 HTTP 通信所建立的 TCP 连接,开始 WebSocket 通信,可以收发多个 TCP 消息。
  • URL 分为两种格式:
    • ws :格式为 ws://host:port/path ,通过 HTTP 协议进行握手,默认使用 TCP 80 端口。
    • wss :格式为 wss://host:port/path ,通过 HTTPS 协议进行握手,默认使用 TCP 443 端口。
  • 客户端的 JS 代码示例:
    var ws = new WebSocket("ws://10.0.0.1/test");
    ws.send("hello");
    ws.send("world");
    ws.close();
    
  • 优点:
    • 通用性强,大部分 HTTP 服务器,都支持切换到 WebSocket 协议。
    • SSE、WebSocket 都允许服务器主动发送消息给客户端。与之相比,HTTP 通信时,服务器遇到紧急消息,不能立即通知客户端,只能等客户端下一次发送 HTTP 请求报文。
    • SSE 只允许服务器发送多条消息,而客户端只能发送一条消息。而 WebSocket 支持全双工通信。
    • SSE 只支持发送 text 格式的数据。而 WebSocket 支持发送任意格式的数据。
  • 缺点:
    • 需要维持 TCP 长连接,会增加服务器的负载。
    • 如果网络不稳定,则 TCP 连接会经常断掉,需要重新 WebSocket 握手。