了解 HTTP 协议
# 了解 HTTP 协议
HTTP 协议全称为 Hyper Text Transfer Protocol(超文本传输协议),是用于客户端和服务器之间的通信的一种协议,它规定了传输信息的格式
HTTP 发展史
# 一、 HTTP1.0
早先 1.0 的 HTTP 版本,是一种无状态、无连接的应用层协议。
# HTTP1.0 存在的问题:
- 无状态、无连接
HTTP1.0 规定浏览器和服务器保持短暂的连接,浏览器的每次请求都需要与服务器建立一个 TCP 连接,服务器处理完成后立即断开 TCP 连接(无连接),服务器不跟踪每个客户端也不记录过去的请求(无状态)。
这种无状态性可以借助cookie
/session
机制来做身份认证和状态记录
- 无法复用连接,无连接的特性导致最大的性能缺陷就是无法复用连接。
- 队头阻塞,由于 HTTP1.0 规定下一个请求必须在前一个请求响应到达之前才能发送。假设前一个请求响应一直不到达,那么下一个请求就不发送,同样的后面的请求也给阻塞了
为了解决这些问题,1.1 出现了
# 二、 HTTP1.1
# 2.1 HTTP 的基本优化方向
影响一个 HTTP 网络请求的因素主要有两个:带宽和延迟。
# 带宽
现在网络基础建设已经使得带宽得到极大的提升,我们不再会担心由带宽而影响网速
# 延迟有几个方面
- 浏览器阻塞
浏览器会因为一些原因阻塞请求。浏览器对于同一个域名,同时只能有 4 个连接(这个根据浏览器内核不同可能会有所差异),超过浏览器最大连接数限制,后续请求就会被阻塞
- DNS 查询
浏览器需要知道目标服务器的 IP 才能建立连接。将域名解析为 IP 的这个系统就是 DNS。这个通常可以利用 DNS 缓存结果来达到减少这个时间的目的
- 建立连接
HTTP 是基于 TCP 协议的,浏览器最快也要在第三次握手时才能捎带 HTTP 请求报文,达到真正的建立连接,但是这些连接无法复用会导致每次请求都经历三次握手和慢启动。三次握手在高延迟的场景下影响较明显,慢启动则对文件类大请求影响较大。
# 2.2 HTTP1.1 优化了什么
对于 HTTP1.1,不仅继承了 HTTP1.0 简单的特点,还克服了诸多 HTTP1.0 性能上的问题,增加了长连接 和 管道化。
# 长连接
HTTP1.1 增加了一个 Connection 字段,通过设置 Keep-Alive 可以保持 HTTP 连接不断开,避免了每次客户端与服务器请求都要重复建立释放建立 TCP 连接,提高了网络的利用率。如果客户端想关闭 HTTP 连接,可以在请求头中携带 Connection: false 来告知服务器关闭请求。
# 管道化
在 HTTP/1.1 版本上使用了一种叫 Pipelining 管道技术的方式,让客户端能够并行发送多个请求
,服务器端也可以并行处理多个
来自客户端的请求。
但这不是真正的并行
- 客户端同时发了两个请求分别来获取 html 和 css,假如说服务器的 css 资源先准备就绪,服务器也会先发送 html 再发送 css。
- 换句话来说,只有等到 html 响应的资源完全传输完毕后,css 响应的资源才能开始传输。也就是说,不允许同时存在两个并行的响应。
🆚 那么 1.1 的并行是怎么回事呢?
在一个TCP连接
中,发送多个 HTTP 请求,不需要等待服务器端对前一个请求的响应之后,再发送下一个请求。但是使用了管道技术的 HTTP/1.1,根据 HTTP/1.1 的规则,服务器端在响应时,要严格按照接收请求的顺序发送,即先接收到的请求,需要先发送其响应,客户端浏览器也是如此,接收响应的顺序要按照自己发送请求的顺序来
需要注意的是,服务器必须按照客户端请求的先后顺序依次回送相应的结果,以保证客户端能够区分出每次请求的响应内容。
# HTTP1.1 还是无法解决队头阻塞的问题
队首阻塞发生在服务器端,虽然服务器端并行接收了多个请求,也并行处理生成多个响应,但由于要遵守 HTTP/1.1 的规则,先接收到的请求需要先发送响应,造成了阻塞问题。
# 三、 HTTP2
HTTP/2 支持在一个 TCP 连接中并行发送多个请求和接收多个响应,无需等待,因为对 HTTP 消息进行二进制分帧的方式进行编码,客户端和服务器端之间的消息传递变成互不干扰的帧,可以交错发送,待接收完之后再组装成完整的消息
HTTP/2 传输数据量的大幅减少,主要有两个原因:以二进制方式传输和 Header 压缩
# 3.1 二进制传输
HTTP/2 采用二进制格式传输数据,而非 HTTP/1.x 里纯文本形式的报文
HTTP/2 将请求和响应数据分割为更小的帧,并且它们采用二进制编码。
把 header 与 data 分成二进制帧,对数据进行顺序标识,这样数据就可以根据顺序标识重新组合
# 3.2 多路复用
下面是几个概念:
- 流(stream):已建立连接上的双向字节流。
- 消息:与逻辑消息对应的完整的一系列数据帧。
- 帧(frame):HTTP2.0 通信的最小单位,每个帧包含帧头部,至少也会标识出当前帧所属的流(stream id)。
每个数据流以消息的形式发送,而消息由一或多个帧组成。这些帧可以乱序发送,然后再根据每个帧头部的流标识符(stream id)重新组装。
可能会导致关键请求被阻塞。HTTP2.0 里每个数据流都可以设置优先级和依赖,优先级高的数据流会被服务器优先处理和返回给客户端,数据流还可以依赖其他的子数据流。
可见,HTTP2.0 实现了真正的并行传输,它能够在一个 TCP 上进行任意数量 HTTP 请求。而这个强大的功能则是基于“二进制分帧”的特性。
# 3.3 Header 压缩
为什么要压缩?在 HTTP/1 中,HTTP 请求和响应都是由「状态行、请求 / 响应头部、消息主体」三部分组成。一般而言,消息主体都会经过 gzip 压缩,或者本身传输的就是压缩过后的二进制文件(例如图片、音频),但状态行和头部却没有经过任何压缩,直接以纯文本传输。
随着 Web 功能越来越复杂,每个页面产生的请求数也越来越多,导致消耗在头部的流量越来越多,尤其是每次都要传输 UserAgent、Cookie 这类不会频繁变动的内容,完全是一种浪费。
# 3.4 服务器推送
HTTP/2 引入了 server push,它允许服务端推送资源给浏览器,在浏览器明确地请求之前。
# 3.5 安全性
HTTP/2 是加密的。也就是说,互联网上通常所能见到的 HTTP/2 都是使用"https”协议名,跑在 TLS 上面。HTTP/2 协议定义了两个字符串标识符:“h2"表示加密的 HTTP/2,“h2c”表示明文的 HTTP/2。
# 四、 HTTP3
虽然 HTTP/2 解决了很多之前旧版本的问题,但是它还是存在一个巨大的问题,主要是底层支撑的 TCP 协议造成的
# 4.1 http2 遗留的问题
- TCP 以及 TCP+TLS 建立连接的延时
HTTP/2 都是使用 TCP 协议来传输的,而如果使用 HTTPS 的话,还需要使用 TLS 协议进行安全传输,而使用 TLS 也需要一个握手过程,这样就需要有两个握手延迟过程
- TCP 的队头阻塞并没有彻底解决
上文我们提到在 HTTP/2 中,多个请求是跑在一个 TCP 管道中的。但当出现了丢包时,HTTP/2 的表现反倒不如 HTTP/1 了。因为 TCP 为了保证可靠传输,有个特别的“丢包重传”机制,丢失的包必须要等待重新传输确认,HTTP/2 出现丢包时,整个 TCP 都要开始等待重传,那么就会阻塞该 TCP 连接中的所有请求
Google 在推 SPDY 的时候就已经意识到了这些问题,于是就另起炉灶搞了一个基于 UDP 协议的“QUIC”协议,让 HTTP 跑在 QUIC 上而不是 TCP 上
# 4.2 QUIC 新功能
- 实现了类似 TCP 的流量控制、传输可靠性的功能。
- 实现了快速握手功能。
- 集成了 TLS 加密功能。
- 多路复用,彻底解决 TCP 中队头阻塞的问题
# 五、 HTTPS
- HTTPS 协议需要到 CA 申请证书,一般免费证书很少,需要交费。
- HTTP 协议运行在 TCP 之上,所有传输的内容都是明文,HTTPS 运行在 SSL/TLS 之上,SSL/TLS 运行在 TCP 之上,所有传输的内容都经过加密的。
- HTTP 和 HTTPS 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
- HTTPS 可以有效的防止运营商劫持,解决了防劫持的一个大问题。