Http相关的协议

Posted by Run-dream Blog on July 22, 2021

HTTP

HTTP 即 (HyperText Transfer Protocol) 超文本传输协议。

用途:

为 Web 浏览器与 Web 服务器之间的通信而设计的,但也可以用于其他目的,比如grpc就使用了http2.0作为传输协议。

组成:

  • 服务端

  • 客户端

  • 传输协议 TCP

  • 报文
    • 起始行
      • 方法
        • GET
        • POST
        • PUT
        • DELETE
        • HEAD
      • 请求URL
      • 版本 HTTP的版本
        • 0.9
        • 1.0
        • 1.1 主流
        • 2.0
      • 状态码 ElasticSearch就使用了状态码来表示请求状态
        • 1xx 信息展示
          • 101 Switching Protocol 比如websocket
        • 2xx 成功
          • 204 No Content
        • 3xx 重定向
          • 301 Moved Permanently
          • 304 Not Modified 协商缓存有用到
        • 4xx 客户端错误
          • 400 Bad Request
          • 401 nauthorized 比如未登录
          • 403 Forbidden 比如无权限
          • 404 Not Found
          • 411 Length Required
          • 414 URI Too Long
          • 429 Too Many Requests 限流
        • 5xx 服务器错误
          • 500 Internal Server Error 比如接口出错
          • 502 Bad Gateway 错误的响应
          • 503 Service Unavailable 服务器因维护或重载而停机
          • 504 Gateway Timeout 不能及时得到响应
    • 首部字段
      • Accept MIME TYPES
      • Cookie
      • Expires
      • If-Modified-Since
      • Keep-Alive
      • Referer
      • User-Agent
    • 主体
  • 基本性质

    • 简单 报文可以读懂
    • 可扩展 headers
    • 无状态有会话 cookie
    • 基于连接
  • 缺点

    太多了,后续的协议一个个来补坑。

DNS

作用:

HTTP中的URL通常使用的是地址信息而非IP信息,所以需要使用DNS服务获取到服务器的IP信息。

A 记录和 CNAME:

A 记录直接指向 IP 地址,CNAME 记录指向域名。

CNAME 记录可用于 CDN 加速,通过 CDN 加速别名解析网站域名,这样既可以起到加速网站的作用,又能隐藏网站的真实 IP,减少被攻击的几率。

解析机制:

因为域名服务器是按照树状结构组织的,因而域名查找是使用递归的方法,并通过缓存的方式增强性能。

优先从本地DNS缓存中读取,如果读取不到则按照下面的顺序

  1. 本地的 DNS 客户端向 DNS 解析器发出解析 github.com 域名的请求;
  2. DNS 解析器首先会向就近的根 DNS 服务器 . 请求顶级域名 DNS 服务的地址;
  3. 拿到顶级域名 DNS 服务 com. 的地址之后会向顶级域名服务请求负责 github.com. 域名解析的命名服务;
  4. 得到授权的 DNS 命名服务时,就可以根据请求的具体的主机记录直接向该服务请求域名对应的 IP 地址;

注意

实践:

  1. 负载均衡 通过CNAME的方式,在不同级别的DNS服务进行处理
    • 内部负载均衡
    • 全局负载均衡
  2. 服务发现

缺点:

  1. 域名缓存问题 本地缓存会让全局负载均衡失败
  2. 域名转发问题 导致无法选择最优服务器
  3. 域名更新问题 在权威 DNS 服务器解析变更的时候,本地 DNS 服务器更新缓慢
  4. 解析延迟问题 要查很多次

HttpDNS:

不走传统的 DNS 解析,而是自己搭建基于 HTTP 协议的 DNS 服务器集群,分布在多个地点和多个运营商。当客户端需要 DNS 解析的时候,直接通过 HTTP 协议进行请求这个服务器集群,得到就近的地址。

HTTPS

HTTP 协议存在的一个很严重的问题是, HTTP 的数据是明文传输的,不做任何加密,相当于在网络上裸奔;容易被中间人恶意篡改,这种行为叫做中间人攻击

而 HTTPS 的核心主要的思想是在http基础上增加了 ssl 安全认证。

加密通信

加密方式的分类:

  • 对称加密 如 DES 只有一个密钥
  • 非对称加密 如 RSA 有公钥私钥之分,私钥用来解密,而公钥用来加密。

HASH算法 如 SHA,来确认信息没有被篡改。

由于非对称加密比对称加密慢,所以HTTPS的实现是公钥私钥主要用于传输对称加密的秘钥,而真正的双方大数据量的通信都是通过对称加密进行的

为什么不直接全部使用对称加密呢?因为,这样的话其他人也可以获取到公钥,从而窃取信息。

证书

现在新的问题又出现了,非对称加密也有公钥,怎么将不对称加密的公钥给对方呢?

一种是放在一个公网的地址上,让对方下载;另一种就是在建立连接的时候,传给对方。

但是这两种方式都不能保证,拿到的公钥不是第三方冒充的。因此 HTTPS 引入了证书的机制。

所谓证书,就是服务端将它的公钥还有一些基本信息,发给 CA,CA用它的私钥对这些信息进行签名。

现在的交互过程变成了,服务端直接把证书发给客户端,客户端通过CA的公钥解析证书是否合法,并获取到服务端的公钥,最后利用这个公钥来进行数据的通信。

证书链

问题现在如何获取CA的公钥呢? 简单的来说,CA是分级别的

  • end-user 包含用来加密传输数据的公钥的证书,是HTTPS中使用的证书

  • intermediates:CA用来认证公钥持有者身份的证书,即确认HTTPS使用的end-user证书是属于 end-user 的证书。这类intermediates证书甚至可以有很多级。

  • root 用来认证intermediates证书是合法证书的证书。

其中,Root Certificates 可以下载安装或者是浏览器或着操作系统内置。

这样就通过证书链来获取到 end-user 证书的公钥了。

HTTP 2.0

新增特性:

  1. 二进制分帧

    HTTP 2.0 还将所有的传输信息分割为更小的消息和帧,并对它们采用二进制格式编码。

    常见的帧有 Header 帧,用于传输 Header 内容,并且会开启一个新的流。再就是 Data 帧,用来传输正文实体。多个 Data 帧属于同一个流。

    在这个机制下,HTTP2.0实现了:

    1. 多路复用 (Multiplexing) / 连接共享
    2. 请求优先级
  2. 头部压缩

    HTTP 1.1 在应用层以纯文本的形式进行通信。每次通信都要带完整的 HTTP 的头,而且不考虑 pipeline 模式的话,每次的过程总是像上面描述的那样一去一回。

    这样在实时性、并发性上都存在问题。为了解决这些问题,HTTP 2.0 会对 HTTP 的头进行一定的压缩,将原来每次都要携带的大量 key value 在两端建立一个索引表,对相同的头只发送索引表中的索引。

  3. 服务端推送

    服务器可以对一个客户端请求发送多个响应,服务器向客户端推送资源无需客户端明确地请求。并且,服务端推送能把客户端所需要的资源伴随着index.html一起发送到客户端,省去了客户端重复请求的步骤。

    注意这里和websocket不同,HTTP2.0则是对HTML、CSS等JS资源的传输方式进行了优化,并没有提供新的JS API,也不能用于实时传输消息。Server是可以主动关闭连接的,所以并不是长连接。

缺点:

因为现在所有的压力集中在底层一个TCP连接之上,TCP很可能就是下一个性能瓶颈,比如TCP分组的队首阻塞问题,单个TCP packet丢失导致整个连接阻塞,无法逃避,此时所有消息都会受到影响。

QUIC

从 TCP 切换到 UDP, 在应用层里面维护连接的机制。

机制:

  1. 自定义连接机制

    不再以四元组(源 IP、源端口、目的 IP、目的端口)标识,而是以一个 64 位的随机数作为 ID 来标识连接,所以当 IP 或者端口变化的时候,只要 ID 不变,就不需要重新建立连接。

  2. 自定义重传机制

    递增的序列号来取代序号应答机制

  3. 阻塞的多路复用

    同一条 QUIC 连接上可以创建多个 stream,来发送多个 HTTP 请求。但是,QUIC 是基于 UDP 的,一个连接上的多个 stream 之间没有依赖

  4. 自定义流量控制

    TCP 的流量控制是通过滑动窗口协议。QUIC 的流量控制也是通过 window_update,来告诉对端它可以接受的字节数。

    只是TCP的流量控制是基于序列号的累计应答,一旦 ACK 了一个序列号,就说明前面的都到了,所以只要前面的没到,后面的到了也不能 ACK,就会导致后面的到了,也有可能超时重传,浪费带宽。

    QUIC 的 ACK 是基于 offset 的,每个 offset 的包来了,进了缓存,就可以应答,应答后就不会重发,中间的空档会等待到来或者重发即可,而窗口的起始位置为当前收到的最大 offset,从这个 offset 到当前的 stream 所能容纳的最大缓存,是真正的窗口大小。

缺陷:

老的硬件不支持。在一些 NAT 网络环境下,UDP 协议会被路由器等中间网络设备禁止

TCP/UDP

比较:

  • 相同点

    1. 都是传输层协议
    2. 都根据端口号,将数据交给相应的应用程序
  • 不同点

    1. 面向连接

      TCP 面向连接 在客户端和服务端建立数据结构来维护双方交互的状态

      UDP 面向无连接

    2. 可靠交互

      TCP 提供可靠交付。

      UDP 继承了 IP 包的特性,不保证不丢失,不保证按顺序到达。

    3. 面向字节流/基于数据报

      TCP 是面向字节流的。发送的时候发的是一个流,没头没尾。

      而 UDP 继承了 IP 的特性,基于数据报的,一个一个地发,一个一个地收。

    4. 拥塞控制

      TCP 是可以有拥塞控制的。包丢弃了或者网络的环境不好了,就会根据情况调整自己的行为

    5. 有无状态

      TCP 其实是一个有状态服务,UDP 则是无状态服务

TCP三次握手和四次挥手:

三次握手:

一句话概括,TCP连接握手,握的是通信双方数据原点的序列号

  • 第一次握手(SYN, seq=x)

    为了验证客户端的发送能力。

    客户端发送一个 TCP 的 SYN 标志位置1的包,指明客户端打算连接的服务器的端口,以及初始序号 X,保存在包头的序列号(Sequence Number)字段里。发送完毕后,客户端进入 SYN_SEND 状态。

  • 第二次握手(SYN, ACK, seq=y, ack=x+1)

    为了验证服务端的接受和发送能力。

    服务器发回确认包(ACK)应答。即 SYN 标志位和 ACK 标志位均为1。服务器端选择自己 ISN 序列号,放到 Seq 域里,同时将确认序号(Acknowledgement Number)设置为客户的 ISN 加1,即X+1。 发送完毕后,服务器端进入 SYN_RCVD 状态。

  • 第三次握手(ACK,ack=y+1)

    为了验证客户端的接受能力。

    客户端再次发送确认包(ACK),SYN 标志位为0,ACK 标志位为1,并且把服务器发来 ACK 的序号字段+1,放在确定字段中发送给对方,并且在数据段放写ISN的+1。

    发送完毕后,客户端进入 ESTABLISHED 状态,当服务器端接收到这个包时,也进入 ESTABLISHED 状态,TCP 握手结束。

四次挥手:

  • 第一次挥手(FIN=1,seq=x)

    假设客户端想要关闭连接,客户端发送一个 FIN 标志位置为1的包,表示自己已经没有数据可以发送了,但是仍然可以接受数据。

    发送完毕后,客户端进入 FIN_WAIT_1 状态。

  • 第二次挥手(ACK=1,ACKnum=x+1)

    服务器端确认客户端的 FIN 包,发送一个确认包,表明自己接受到了客户端关闭连接的请求,但还没有准备好关闭连接。

    发送完毕后,服务器端进入 CLOSE_WAIT 状态,客户端接收到这个确认包之后,进入 FIN_WAIT_2 状态,等待服务器端关闭连接。

  • 第三次挥手(FIN=1,seq=y)

    服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN 置为1。

    发送完毕后,服务器端进入 LAST_ACK 状态,等待来自客户端的最后一个ACK。

  • 第四次挥手(ACK=1,ACKnum=y+1)

    客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入 TIME_WAIT状态,等待可能出现的要求重传的 ACK 包。

    服务器端接收到这个确认包之后,关闭连接,进入 CLOSED 状态。

    客户端等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入 CLOSED 状态。

参考资料

HTTP教程

为什么 DNS 使用 UDP 协议

HTTP2

趣谈网络协议

证书链-Digital Certificates