HTTP各版本区别
dd

HTTP1.0与HTTP1.1的区别

长连接

  • HTTP1.0默认适用短链接,客户端和服务器每进行一次HTTP交互就需要建立一次连接,任务结束就中断连接

  • HTTP1.1默认使用长连接,只要任意一端没有明确提出断开连接,就一直保持TCP连接状态

管道网络传输

  • HTTP1.0需要收到第一个请求的回应后才可以发送第二个请求

  • HTTP1.1使用长连接,使管道网络传输成为可能。在同一个TCP连接中,客户端可以发起多个请求,只要第一个请求发送出去了就可以发送第二个,不需要等待第一个请求的返回,可以减少整体的响应时间

Host域

  • HTTP1.0认为每台服务器都绑定一个唯一的IP地址,因此请求消息中的URL没有传递主机名,但是随着虚拟主机技术的发展,一台物理服务器上可以存在多个虚拟主机,共享一个IP地址,也就是说一个IP地址是可以对应多个域名的

    • 比如一台IP为A的服务器上部署着谷歌、百度、淘宝的网站,在发送请求时域名解析会解析到同一个IP地址,那么如何区分用户是要具体访问主机中的哪一个应用

    • 使用ip+port区分

      • 需要为每个网站部署一个端口,客户端在访问的时候需要直到是哪一个端口
    • 虚拟主机

      • 将一台完整的服务器分成若个主机,可以在单一主机上运行多个服务,客户端就可以使用同一个ip和同一个端口号访问不同的网站,通过host域进行区分

      • 通过用户请求的host域名进行区分,服务器后台解析出host域并和服务器上设置的server_name比对,如果匹配则访问,不匹配则连接丢弃报错

  • HTTP1.1增加Host域且请求消息中如果没有Host域会报告错误400Bad Request

断点续传

  • HTTP1.0每次只会传输整个数据实体,没办法部分传输

  • HTTP1.1默认支持断点续传,原理是在请求报文头中加入Range字段段

消息通知管理

  • HTTP1.1新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源当前状态冲突;410(Gone)表示服务器上某个资源被永久性删除

缓存处理

  • HTTP1.0使用header中的if-modified-since和expires作为缓存判断标准

  • HTTP1.1引入了更多缓存控制策略如Entity tag,If-Unmodified-Since,If-match,If-None-Match等

HTTP1.1和HTTP2.0的区别

头部压缩

  • HTTP1.1中Header问题

    • 固定的字段占字节大

    • 大量的请求和响应报文中许多字段重复

    • 只对body进行压缩,没有对header进行压缩

  • HTTP2.0使用HPACK算法对header的数据进行压缩

    • HPACK算法:在客户端和服务器两端建立字典,将字段存入字典中并生成索引号,使用索引号代表字段了

      • 静态字典

        • 为高频出现在头部的字符串和字段建立静态表,写入HTTP/2框架中
      • 动态字典

        • 不在静态表范围内的头部字符串要自行构建动态表,Index从62起步,在编码解码的时候随时更新,下一次发送的时候就只需要发送一个字节的index

        • 必须同一个连接上重复传输完全相同的HTTP头部

        • 占用内存越来越大

    • 哈夫曼编码压缩整数和字符串

二进制格式

  • 二进制:体积小、速度块、没有歧义

    • 对人不友好,但是对计算机友好,可以直接解析二进制报文,增加了数据传输效率
  • HTTP1.1的报文使用文本格式,HTTP2.0使用二进制格式

  • 将报文分为头信息帧和数据帧

  • 头信息帧的最后4个字节是流标识符,最高位被保留不用,流标识位用于表示该Fream属于哪个Stream,接收方可以根据该信息从乱序的帧中找到相同Stream ID的帧从而有序组装信息

多路复用

  • HTTP2.0将每一个请求看成是一个流,为每个请求分配一个唯一的流id,并将请求分成多个块,不同的Stream的块是可以混杂在一起发送的,因此可以并发不同的请求

  • 流的特点

    • 流是可并发的,一个HTTP2连接上可以同时发出多个流传输数据

    • 每一个流有唯一的流ID,客户端发出为奇数,服务器为偶数

    • StreamID不可复用,只能顺序递增,使用完后需要发出控制帧GOAWAY关闭TCP连接

    • 第0号流不能关闭,不能发送数据帧,只能发送控制帧,用于流量控制

服务端推送

  • HTTP1.1每一个网络资源都必须由客户端明确地请求

  • HTTP2服务器可以主动向客户端发送消息

  • 例如浏览器请求HTML时提前将可能用到的js等静态资源主动发送给客户端减少延时等待与避免请求

优先级

  • 客户端可以指定数据流的优先级

HTTP3.0与HTTP2.0的区别

HTTP2是基于TCP协议的

  • 存在队头阻塞

  • TCP和TLS握手时延,至少需要3RTT

  • 网络迁移需要重新连接

HTTP3将下层的TCP协议更改为UDP协议并增加了QUIC协议

  • QUIC是一个在UDP上的伪TCP+TLS+HTTP2的多路复用协议

  • 解决HTTP2队头阻塞问题

    • UDP不关心包的顺序,但是QUIC会

    • QUIC保证包的可靠性,每个数据包都有一个序号唯一标识,当某个流的数据包丢失了,即使这个流的其他数据包到了也没办法被HTTP3读取,只有QUIC重传丢失的报文才会交给HTTP3

    • 其他流的数据包只要被完整接受就可以被HTTP3读取

    • QUIC 连接上的多个 Stream 之间并没有依赖,都是独立的,某个流发生丢包了,只会影响该流,其他流不受影响

  • 更快的连接建立

    • HTTP/1 和 HTTP/2 协议,TCP 和 TLS 是分层的,分别属于内核实现的传输层、OpenSSL 库实现的表示层,因此它们难以合并在一起,需要分批次来握手,先 TCP 握手,再 TLS 握手

    • HTTP/3 的 QUIC 协议并不是与 TLS 分层,而是 QUIC 内部包含了 TLS,它在自己的帧会携带 TLS 里的“记录”,再加上 QUIC 使用的是 TLS 1.3,因此仅需 1 个 RTT 就可以「同时」完成建立连接与密钥协商,甚至在第二次连接的时候,应用数据包可以和 QUIC 握手信息(连接信息 + TLS 信息)一起发送,达到 0-RTT 的效果

    • HTTP/3 在传输数据前虽然需要 QUIC 协议握手,这个握手过程只需要 1 RTT,握手的目的是为确认双方的「连接 ID」,连接迁移就是基于连接 ID 实现的

  • 连接迁移

    • 基于TCP传输协议的HTTP协议是通过四元组确定一条TCP连接,当设备从一个网络切换到另一个网络的时候IP地址改变了,就需要断开连接重新建立连接

    • QUIC没有使用四元组绑定连接,而是通过连接ID标识通信的两个端点,客户端和服务器各选择一组ID标识自己,因此即使移动设备网络变化导致IP地址变化了,只要仍然有上下文信息(连接ID、TLS密钥等)就可以无缝复用原连接了,消除重连成本

HTTP3协议

  • HTTP/3 同 HTTP/2 一样采用二进制帧的结构,不同的地方在于 HTTP/2 的二进制帧里需要定义 Stream,而 HTTP/3 自身不需要再定义 Stream,直接使用 QUIC 里的 Stream,于是 HTTP/3 的帧的结构也变简单了

  • HTTP/3 在头部压缩算法这一方面也做了升级,升级成了 QPACK。与 HTTP/2 中的 HPACK 编码方式相似,HTTP/3 中的 QPACK 也采用了静态表、动态表及 Huffman 编码。

  • 对于静态表的变化,HTTP/2 中的 HPACK 的静态表只有 61 项,而 HTTP/3 中的 QPACK 的静态表扩大到 91 项。

  • HTTP/2 和 HTTP/3 的 Huffman 编码并没有多大不同,但是动态表编解码方式不同。

  • 所谓的动态表,在首次请求-响应后,双方会将未包含在静态表中的 Header 项更新各自的动态表,接着后续传输时仅用 1 个数字表示,然后对方可以根据这 1 个数字从动态表查到对应的数据,就不必每次都传输长长的数据,大大提升了编码效率。

  • 可以看到,动态表是具有时序性的,如果首次出现的请求发生了丢包,后续的收到请求,对方就无法解码出 HPACK 头部,因为对方还没建立好动态表,因此后续的请求解码会阻塞到首次请求中丢失的数据包重传过来

    • QUIC 会有两个特殊的单向流,所谓的单向流只有一端可以发送消息,双向则指两端都可以发送消息,传输 HTTP 消息时用的是双向流,这两个单向流的用法:

    • 一个叫 QPACK Encoder Stream,用于将一个字典(Key-Value)传递给对方,比如面对不属于静态表的 HTTP 请求头部,客户端可以通过这个 Stream 发送字典;

    • 一个叫 QPACK Decoder Stream,用于响应对方,告诉它刚发的字典已经更新到自己的本地动态表了,后续就可以使用这个字典来编码了。

    • 这两个特殊的单向流是用来同步双方的动态表,编码方收到解码方更新确认的通知后,才使用动态表编码 HTTP 头部

    • 也就是说要更新动态表前先通知对方,只有在得到对方的响应后才可以使用动态表中的内容