HTTP1
超文本协议
每次都需要重新建立连接,增加延迟。
为了性能考虑,引入雪碧图,将小图内联,减少请求数; 以及打开多个持久连接。
短连接的缺点:
TCP建立连接需要1.5RTT, TCP断开连接需要2RTT,握手挥手成本太高。
HTTP1.1
超文本协议,在 HTTP/1.1 版中,报文的头信息必须是文本(ASCII 编码),数据体可以是文本,也可以是二进制
相对HTTP1.0
- 增了很多方法,如 PUT、HEAD、OPTIONS 等;
- 加入
connection:keep-alive可以复用一部分连接; - 新增了
host字段,用来指定服务器的域名; - 缓存方面的区别,在 http1.0 中主要使用 header 里的
If-Modified-Since,Expires来做为缓存判断的标准,http1.1 则引入了更多的缓存控制策略例如Etag、If-Unmodified-Since、If- Match、If-None-Match等更多可供选择的缓存头来控制缓存策略; - 引入了
range头域,它允许只请求资源的某个部分,即返回码是 206(Partial Content),这样就方便了开 发者自由的选择以便于充分利用带宽和连接。
HTTP1.1缺陷:
高延迟: 浏览器限制了同一域名下同一时刻的请求数量,当页面需要很多资源的时候,
队头阻塞导致达到最大的请求数时,剩余资源需等待前序请求完成才能发起。【HTTP2多路复用可解决】,虽然建立了长连接,是双向通信,但任意一个时间点实际还是单向的。
无状态特性 — 阻碍交互
明文传输 — 不安全性
不支持服务端推送
HTTP1.1的队头阻塞:
多个请求可以复用同一个 TCP 连接,但是在同一个 TCP 连接里面,数据请求的通信次序 是固定的。服务器只有处理完一个请求的响应后,才会进行下一个请求的处理,如果前面请求的响应特别慢的话,就会造成许多请求排队等待的情况,这种情况被称为“队头堵塞”。队头阻塞会导致持久连接在达到最大数量时,剩余的资源需要等待其他资源请求完成后才能发起请求。
队头阻塞是由HTTP“请求-应答”模型所导致的。因为HTTP规定报文必须是“一发一收”,这样就形成一个先进先出的串行队列。队列中请求没有轻重缓急的优先级,只有入队的先后顺序,排在前的优先处理。如果队首请求处理太慢,那后面所有的请求都不得不等待。
HTTP2
二进制协议, 头信息和数据体都是二进制,并且统称为"帧",可以分为头信息帧和数据帧。
底层支撑协议是TCP
非常重要的概念,
帧和流。
帧代表最小数据单位,会标识所属哪个流。
流是多个帧汇成流。
特性:
二进制分帧:
HTTP1.X是超文本传输协议, HTTP2是二进制协议,即所有的传输数据(头和主体)被分割,采用二进制编码。帧头共9个字节。
上述帧头解释:
00 01 0a 标识帧长度;
01 标识帧类型;
0X25 表示标志位;
00 00 00 01 流标识;
多路复用:
只需要建立一次TCP连接,浏览器和服务器可同时发送多个请求或者响应,而且不用按照顺序一一发送,避免了队头阻塞。
一般来说,一个域名下只需要一个TCP连接,若该连接中出现了丢包,则http2的性能远不及http1,丢包导致tcp重传,就导致了后面所有的数据都被阻塞。队头阻塞没有彻底解决
数据流:
二进制帧的
双向传输序列,可并发
当客户同时向服务端发送多个请求的时候,每个请求会被分解成一个个帧,每个帧都会在TCP链路中无序的传输,同一个连接里面连续的数据包,可能属于不同的请求。同一个请求的帧stream Id都是一样的,当帧到达服务之后,就可以按照stream Id重新组合完整的请求。HTTP/2 将每个请求或回应的所有数据包,称为一个数据流
头部压缩HPACK:
请求和相应首部压缩,客户端和服务端共同维护一张头索引表(静态表 + 动态表),所有字段在这个表里,生成一个索引号,通过发送索引号提高速度。
HPACK经过两步:
1)传输value会经过一遍哈夫曼编码来节省流;
2)为了server和client同步,两边都要保留一份headerList,并且每次发送请求时都会检查更新。
Tips:
伪头字段: 为了方便管理和压缩,HTTP/2废除了起始行的概念,把起始行中的请求方法、URI、状态码等统一转换成了头字段,比如":method",会在header key之前加一个冒号。
静态表:常用字段;
动态表:其他头,添加在静态表后面,会在编码解码时更新;
服务端推送:
服务端主动向客户端推送数据。
eg. 客户端请求一个html,服务端把html文件返回客户端后,还会把相应的css文件推送给客户端。
HTTP2缺陷
TCP 以及 TCP+TLS 建立连接的延时
TCP 的队头阻塞并没有彻底解决(复用一个连接导致),原因是重传机制,只解决了应用层的队头阻塞。
多路复用导致服务器压力上升
多路复用容易 Timeout
HTTP3
使用一个基于 UDP 协议的 QUIC (Quick UDP Internet Connection)协议。摒弃TCP
QUIC——基于 UDP 实现,是 HTTP3 中的底层支撑协议,该协议基于 UDP,又取了 TCP 中的精华,实现了即快又可靠的协议, 但QUIC不是建立在TLS之上的,而是“内部包含”了TLS,本身就支持加密。
非常重要的概念:
帧和包,以及连接ID。
QUIC使用不透明的“连接ID”来标记通信的两个端点,客户端和服务端可以自行选择一组ID来标记自己,这样就解除了TCP里链接对“IP+Port”的强绑定,支持“连接迁移”。我描述一个场景来体会这个ID带来的变革:下班回家,手机由4G变为wifi,这时IP地址会发生变化,TCP就必须中断重新建立连接,而QUIC连接里,两端的ID不会变,所以连接在“逻辑上”没有中断,他就可以在新的ip上继续使用之前的连接,消除重连成本,实现连接的无缝迁移。
包:
流:
- 多路复用
虽然 HTTP2 支持了多路复用,但是 TCP 协议终究是没有这个功能的。QUIC 原生就实现了这个功能,并且传输的单个数据流可以保证有序交付且不会影响其他的数据流,这样的技术就解决了之前 TCP 存在的问题。
且 QUIC 在移动端的表现也会比 TCP 好。因为 TCP 是基于 IP 和端口去识别连接的,这种方式在多变的移动端网络环境下 是很脆弱的。但是
QUIC 是通过 ID 的方式去识别一个连接,不管你网络环境如何变化,只要 ID 不变,就能迅速重连上。
- 0-RTT
通过使用类似 TCP 快速打开的技术,缓存当前会话的上下文,在下次恢复会话的时候,只需要将之前的缓存传递给服务端验证通过就可以进行传输了。(完成QUIC交易的连接的Session ID会缓存在浏览器内存里,如果用户再次打开该页面,无需建立TLS连接,直接使用缓存Session ID 对应的加密参数,服务器可以根据Session ID在缓存里查找对应的加密参数,并完成加密。)
- 纠错机制
假如说这次我要发送三个包,那么协议会算出这三个包的异或值
并单独发出一个校验包,也就是总共发出了四个包。当出现其中的非校验包丢包的情况时,可以通过另外三个包计算出丢失的数据包的内容。当然这种技术只能使用在丢失一个非校验包的情况下,如果出现丢失多个包就不能使用纠错机制了,只能使用重传的方式了。
一个好问题: