开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第10天,点击查看活动详情
一、HTTP/0.9(单行协议)
这个协议诞生在1991年,大部分人的感觉应该和我一样,不了解,不清楚,更没有使用过。其实它是最好的HTTP协议,相当于一个雏形,该作用是传输传输超文本内容 HTML。
协议定义了客户端发起请求、服务端响应请求的通讯方式。请求报文也只有简单的一行:(一旦连接到服务器,协议、服务器、端口号这些都不是必须的)
GET + 请求的文件路径
服务端收到请求后返回一个以 ASCII 字符流编码的 HTML 文档
<HTML>
这是一个非常简单的 HTML 页面
</HTML>
瓶颈:
- 只支持HTML传输,其余类型的文件没办法传输
- 文件格式仅限于 ASCII 字符流编码
- 只能是GET请求
二、HTTP1.0(构建可扩展性)
随着互联网和浏览器的出现,单纯的文本已经无法满足用户的需求,浏览器希望通过HTTP来传输脚本、样式、图片、音频和视频等不同类型的文件。所以HTTP1.0在1996年诞生了。
首先,它任何格式的内容都可以传输。不再限制为文档。相对于HTTP/0.9增加了下列主要特性:
- 除了GET命令,还引入了POST、HEAD命令
- 每次通信必须包括头信息(HTTP header),即引入了请求头和响应头许,允许传输元数据,使协议变得非常灵活,更具扩展性。
- 增加了响应状态码,标记可能的错误原因
- 传输的数据不再局限于文本
- 支持长连接(但默认还是使用短连接),缓存机制,以及身份认证
相对于HTTP/0.9的最大的改变就是支持头部信息,这样请求头部可以通过Accept告诉服务器可以接收的文件类型。头部字段不仅解决了不同类型文件传输的问题,还增加了缓存和认证功能。
可以看下官网提供的请求的例子:
GET / HTTP/1.0
User-Agent: NCSA_Mosaic/2.0 (Windows 3.1)
Accept: */*
服务端响应的消息
200 OK
Date: Tue, 15 Nov 1994 08:12:31 GMT
Server: CERN/3.0 libwww/2.17
Content-Type: text/html
<HTML>
一个包含图片的页面
<IMG SRC="/myimage.gif">
</HTML>
瓶颈:
- HTTP/1.0中,每进行一次HTTP通讯,都需要建立TCP连接、传输HTTP数据和断开连接三个阶段,无形中增加了无谓的开销
- HTTP/1.0,只有前面的请求返回才能进行下一次请求,如果某个请求没返回,会引起队头阻塞(head of line blocking)
- 每个域名绑定唯一的IP地址,因此一个服务器只能支持一个域名。
- 存在带宽浪费的情况,例如我只需要对象的一部分数据,但是却把所有数据传输回来,并且不支持断点续传
三、HTTP1.1(标准化的协议)
1997年1月,HTTP/1.1 版本发布,目前是最流行的版本,它解决了HTTP1.0中的一些问题
3.1 持久连接
引入了持久连接(persistent connection),即TCP默认是不关闭的,可以被多个请求复用。在HTTP1.1中默认开启Connection: keep-alive
客户端和服务器发现对方一段时间没有活动,就可以主动关闭连接。但是,比较规范的做法是,客户端发送最后一个请求时,Connection: close,明确要求服务器关闭TCP连接。
注意: 目前,对于同一个域名,大多数浏览器允许同时建立6个持久连接。
3.2 管道机制
管道机制(pipelining):在同一个TCP连接里面,客户端可以同时发送多个请求,以降低通信延迟
若发送多个来连接,HTTP1.0的做法是,先发送A请求,然后等待服务器响应,收到回应后到国内B请求。 管道机制的出现,允许客户端同时发送A请求和B请求。但是服务端的处理是按顺序回应,即先回应A请求,后回应B请求
3.3 资源请求方面,引入了range 头域
在 HTTP1.0 中,存在一些浪费带宽的现象,HTTP1.1引入了range 头域,它允许只请求资源的某个部分,即返回码是 206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。支持断点续传。
3.4 分块传输编码
允许响应数据分块(chunked),利于传输大文件。
只要请求或回应的头信息有Transfer-Encoding字段,就表明回应将由数量未定的数据块组成。
3.5 缓存方面优化
HTTP/1.1在1.0的基础上加入了一些cache的新特性.
在HTTP1.0 中主要使用 header 里的 If-Modified-Since、Expires 来做为缓存判断的标准,HTTP1.1 则引入了更多的缓存控制策略,例如 Etag、If-Unmodified-Since、If-Match、If-None-Match 等更多可供选择的缓存头来控制缓存策略。
3.6 提供了虚拟主机的功能(HOST域)
HTTP1.1中增加Host字段,用来表示当前的域名地址,从而服务器就可以根据不同的host做出不同的处理。
可以采用CDN实现域名分片机制,当引入CDN后,每个域名可以维护6个连接,大大减少了资源的下载时间
3.7 其他
新增请求方法:PUT、PATCH、HEAD、 OPTIONS、DELETE。
3.8 瓶颈
瓶颈:
- 虽然允许了TCP复用,但同一个TCP连接中,所有的数据通信是按次序进行的。服务器只有处理完一个回应,才会进行下一个回应。要是前面的回应特别慢,后面就会有许多请求排队等着。则形成了队头堵塞(Head-of-line blocking)。
- 请求 / 响应头部(Header)未经压缩就发送,首部信息越多延迟越大。只能压缩 Body 的部分。
- 请求只能从客户端开始,服务器只能被动响应
四、HTTP2(为了更优的表现)
目的:解决性能瓶颈,通过支持请求和响应的多路复用来减少延迟,通过压缩HTTP首部字段降低协议开销,同时也增加了服务端推送。
4.1 二进制分帧
HTTP/1.1 版的头信息肯定是文本(ASCII编码),数据体可以是文本,也可以是二进制。
HTTP 2.0 的所有帧都采用二进制编码,头部信息和数据体都是二进制,称为头信息帧和二进制帧。
注意:通过二进制分帧实现了HTTP的多路复用。
帧: HTTP/2通信的最小单位,包括帧首部,流标识符、优先值和帧净荷
消息: 是指逻辑上的 HTTP 消息,比如请求、响应等,一系列数据帧组成一个完整的消息。
流: 流是连接中的一个虚拟信道,可以承载双向的消息;每个流都有一个唯一的整数标识符(1、2 … N);为了防止两端流ID冲突,客户端发的流具有奇数ID,服务端发起的流具有偶数ID
4.2 多路复用
HTTP/2 实现了多路复用,HTTP/2 仍然复用 TCP 连接,但是在一个连接里,客户端和服务器都可以同时发送多个请求或回应,而且不用按照顺序一一发送,这样就避免了"队头堵塞"的问题。
例如:服务器同时收到了A请求和B请求,于是先回应A请求,结果发现处理过程非常耗时,于是就发送A请求已经处理好的部分, 接着回应B请求,完成后,再发送A请求剩下的部分。
4.3 数据流
因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应。因此,必须要对数据包做标记,指出它属于哪个回应。HTTP/2 将每个请求或回应的所有数据包,称为一个数据流。每个数据流都有一个独一无二的编号。数据包发送时,都必须标记数据流 ID ,用来区分它属于哪个数据流。
客户端还可以指定数据流的优先级。优先级越高,服务器就会越早回应。0表示最高优先级
4.4 头信息压缩
在HTTP/1.1中,头部信息是不经过压缩的,浪费很多带宽,也影响速度。
HTTP/2 进行了优化,引入了头信息压缩机制。
- 头信息使用 gzip 或 compress 压缩后再发送
- 客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就能提高速度了。
4.5 服务端推送
HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送。使用服务器推送提前给客户端推送必要的资源,这样就可以相对减少一些延迟时间。这里需要注意的是 http2 下服务器主动推送的是静态资源,和 WebSocket 以及使用 SSE 等方式向客户端发送即时数据的推送是不同的。
在阮一峰的教程中,给出了常用的场景:
常见场景是客户端请求一个网页,这个网页里面包含很多静态资源。正常情况下,客户端必须收到网页后,解析HTML源码,发现有静态资源,再发出静态资源请求。其实,服务器可以预期到客户端请求网页后,很可能会再请求静态资源,所以就主动把这些静态资源随着网页一起发给客户端了。
4.6 瓶颈
传输基于TCP,TCP 是字节流协议,TCP 层必须保证收到的字节数据是完整且连续的。我们知道在HTTP/2中,多个请求是跑在一个TCP管道中的,如果其中任意一路数据流中出现了丢包的情况,那么就会阻塞该TCP连接中的所有请求。
- TCP对头堵塞问题
- TCP建立连接超时
五、HTTP3.0
HTTP3.0是为了解决HTTP2.0应运而生的产物。HTTP3的实现思路是:HTTP2 Slimmed + Quic协议。
HTTP3.0,也称作HTTP over QUIC。HTTP3.0的核心是QUIC(读音quick)协议。QUIC协议是基于UDP实现的。
QUIC协议的优点:
- 无队头阻塞
- HTTP2.0协议的多路复用机制解决了HTTP层的队头阻塞问题,但是在TCP层仍然存在队头阻塞问题。
- TCP协议在收到数据包之后,这部分数据可能是乱序到达的,但是TCP必须将所有数据收集排序整合后给上层使用,如果其中某个包丢失了,就必须等待重传,从而出现某个丢包数据阻塞整个连接的数据使用。
- QUIC协议是基于UDP协议实现的,在一条链接上可以有多个流,流与流之间是互不影响的,当一个流出现丢包影响范围非常小,从而解决队头阻塞问题。 -连接建立更快
- 基于TCP协议和TLS协议的HTTP2.0在真正发送数据包之前需要花费一些时间来完成握手和加密协商,完成之后才可以真正传输业务数据。
- QUIC则第一个数据包就可以发业务数据,从而在连接延时有很大优势,可以节约数百毫秒的时间。
- 支持连接迁移
- Quic抛弃了原有的传输层四元组(两个套接字),采用了一个Connection ID的形式来标记端。只要对方的IP地址不变(比如服务器),使用Connection ID,能够无缝地实现发送端的地址更改,在不需要建立连接的情况下,快速实现连接迁移。(因为不需要重新握手)