Skip to content

协议

HTTP协议

1.HTTP

在 HTTP/1 中,为了性能考虑,我们会引入雪碧图、将小图内联、使用多个域名等等的方式。这一切都是因为浏览器限制了同一个域名下的请求数量(Chrome 下一般是限制六个连接),当页面中需要请求很多资源的时候,队头阻塞(Head of line blocking)会导致在达到最大请求数量时,剩余的资源需要等待其他资源请求完成后才能发起请求。 HTTP 版本中,我们是通过文本的方式传输数据。 在 HTTP/1 中,我们使用文本的形式传输 header,在 header 携带 cookie 的情况下,可能每次都需要重复传输几百到几千的字节。

2.HTTP1.1

http1.0中,客户端每隔很短的时间,都会对服务器发出请求,查看是否有新的消息,只要轮询速度足够快,例如1秒,就能给人造成交互是实时进行的印象。这种做法是无奈之举,实际上对服务器、客户端双方都造成了大量的性能浪费。

(1)长连接

HTTP1.1中,通过使用Connection:keep-alive进行长连接,。客户端只请求一次,但是服务器会将继续保持连接,当再次请求时,避免了重新建立连接。

(2)长连接中的管线化

长连接时,默认的请求这样的:请求1 --> 响应1 -->请求2 --> 响应2 --> 请求3 --> 响应3 管线化就是,我把现在的请求打包,一次性发过去,你也给我一次响应回来。

3.HTTP2

(1)多路复用

它引入了 帧(frame)和流(stream),因为 HTTP/1.x 是基于文本的,因为是文本,就导致了它必须是个整体,在传输是不可切割的,只能整体去传 既然,HTTP/2 是基于二进制流的,它就可以把 HTTP 消息分解为独立的帧,交错发送,然后在另一端通过帧中的标识重新组装,这就是多路复用 这就实现了在同一个TCP连接中,同一时刻可以发送多个请求和响应,且不用按照顺序一一对应,即使某个请求任务耗时严重,也不会影响到其它连接的正常执行

INFO

HTTP/1.x keep-alive 与 HTTP/2 多路复用区别:

HTTP/1.x 是基于文本的,只能整体去传;HTTP/2 是基于二进制流的,可以分解为独立的帧,交错发送

HTTP/1.x keep-alive 必须按照请求发送的顺序返回响应;HTTP/2 多路复用不按序响应

HTTP/1.x keep-alive 为了解决队头阻塞,将同一个页面的资源分散到不同域名下,开启了多个 TCP 连接;HTTP/2 同域名下所有通信都在单个连接上完成

HTTP/1.x keep-alive 单个 TCP 连接在同一时刻只能处理一个请求(两个请求的生命周期不能重叠);HTTP/2 单个 TCP 同一时刻可以发送多个请求和响应

(2)二进制编码

在 HTTP/2 中引入了新的编码机制,所有传输的数据都会被分割,并采用二进制格式编码。

(3)Header 压缩

在 HTTP /2 中,使用了 HPACK 压缩格式对传输的 header 进行编码,减少了 header 的大小。并在两端维护了索引表,用于记录出现过的 header ,后面在传输过程中就可以传输已经记录过的 header 的键名,对端收到数据后就可以通过键名找到对应的值。

(4)服务端 Push

在 HTTP/2 中,服务端可以在客户端某个请求后,主动推送其他资源。可以想象以下情况,某些资源客户端是一定会请求的,这时就可以采取服务端 push 的技术,提前给客户端推送必要的资源,这样就可以相对减少一点延迟时间。当然在浏览器兼容的情况下你也可以使用 prefetch 。

缺点: 因为 HTTP/2 使用了多路复用,一般来说同一域名下只需要使用一个 TCP 连接。当这个连接中出现了丢包的情况,那就会导致 HTTP/2 的表现情况反倒不如 HTTP/1 了。因为在出现丢包的情况下,整个 TCP 都要开始等待重传,也就导致了后面的所有数据都被阻塞了。但是对于 HTTP/1 来说,可以开启多个 TCP 连接,出现这种情况反到只会影响其中一个连接,剩余的 TCP 连接还可以正常传输数据。

4.HTTP3

基于这个原因,Google 就更起炉灶搞了一个基于 UDP 协议的 QUIC 协议,并且使用在了 HTTP/3 上,当然 HTTP/3 之前名为 HTTP-over-QUIC,从这个名字中我们也可以发现,HTTP/3 最大的改造就是使用了 QUIC。QUIC 虽然基于 UDP,但是在原本的基础上新增了很多功能,比如多路复用、0-RTT、使用 TLS1.3 加密、流量控制、有序交付、重传等等功能。

(1)多路复用

虽然 HTTP/2 支持了多路复用,但是 TCP 协议终究是没有这个功能的。QUIC 原生就实现了这个功能,并且传输的单个数据流可以保证有序交付且不会影响其他的数据流,这样的技术就解决了之前 TCP 存在的问题。 并且 QUIC 在移动端的表现也会比 TCP 好。因为 TCP 是基于 IP 和端口去识别连接的,这种方式在多变的移动端网络环境下是很脆弱的。但是 QUIC 是通过 ID 的方式去识别一个连接,不管你网络环境如何变化,只要 ID 不变,就能迅速重连上。

HTTP/2 的多路复用是基于 TCP 协议实现的。当一个 TCP 连接中的一个数据包丢失时,TCP 的拥塞控制机制会使得整个连接暂停数据传输,等待丢失的数据包被重传并确认接收。这就导致了即使其他的数据包已经到达,也必须等待,这被称为队头阻塞。因此,虽然 HTTP/2 实现了多路复用,但在丢包率较高的网络环境下,其性能可能会受到影响。

HTTP/3 的多路复用则是基于 QUIC 协议实现的,QUIC 协议是基于 UDP 的。与 TCP 不同,QUIC 协议为每个数据流提供了独立的拥塞控制,因此一个数据流中的数据包丢失不会影响其他数据流。这意味着即使在丢包率较高的网络环境下,HTTP/3 也能保持较高的性能。

(2)0-RTT

通过使用类似 TCP 快速打开的技术,缓存当前会话的上下文,在下次恢复会话的时候,只需要将之前的缓存传递给服务端验证通过就可以进行传输了。

HTTP/3 的 0-RTT 是基于 QUIC 协议实现的。具体的实现过程如下:

在客户端和服务器首次建立连接时,服务器会生成一个新的会话票证(Session Ticket)并发送给客户端。这个会话票证包含了用于恢复会话的信息,例如加密参数等。

客户端将这个会话票证保存下来,用于后续的连接恢复。

当客户端需要重新建立连接时,它会在握手请求中包含这个会话票证,并且在握手过程中就开始发送数据。这就是所谓的 0-RTT 数据。

服务器在收到握手请求后,会验证会话票证。如果验证通过,服务器就会接受 0-RTT 数据,并且继续握手过程。

需要注意的是,由于 0-RTT 数据可能会被重放攻击,因此它通常只用于非敏感的数据传输。对于需要保证安全性的数据,应该等待握手过程完成后再进行传输。

重放攻击,也被称为回放攻击,是一种网络攻击手段。攻击者会截获并记录网络上的数据传输,然后在之后的某个时间点,将这些数据重新发送到网络上,以此来欺骗接收者。

在 HTTP/3 的 0-RTT 中,重放攻击可能会发生。例如,攻击者可以截获并记录客户端发送的 0-RTT 数据,然后在之后的某个时间点,将这些数据重新发送到服务器。由于服务器无法区分这些数据是客户端新发送的,还是被攻击者重放的,因此可能会接受这些数据,导致安全问题。

为了防止重放攻击,一种常见的方法是使用时间戳或序列号。例如,服务器可以为每个会话生成一个唯一的序列号,并且只接受序列号比当前已知的最大序列号大的数据。这样,即使攻击者重放了旧的数据,由于序列号已经过期,服务器也不会接受。

另一种方法是使用一次性的令牌。服务器为每个会话生成一个唯一的令牌,并且每个令牌只能使用一次。这样,即使攻击者重放了数据,由于令牌已经被使用过,服务器也不会接受。

(3)纠错机制

假如说这次我要发送三个包,那么协议会算出这三个包的异或值并单独发出一个校验包,也就是总共发出了四个包。 当出现其中的非校验包丢包的情况时,可以通过另外三个包计算出丢失的数据包的内容。