版本
一、HTTP 0.9
1991
年HTTP 0.9
版,只有一个GET
,而且只支持纯文本内容,早已过时就不讲了
二、HTTP 1.0
2.1 特点
-
任意数据类型都可以发送
-
有
GET
、POST
、HEAD
三种方法 -
无法复用
TCP
连接(长连接) -
有丰富的请求响应头信息。以
header
中的Last-Modified/If-Modified-Since
和Expires
作为缓存标识
三、HTTP 1.1
3.1 特点
优点:
-
持久连接(
persistent connection
),即TCP
连接默认不关闭,可以被多个请求复用,不用声明Connection: keep-alive
。长连接的连接时长可以通过请求头中的keep-alive
来设置 -
管道机制(
pipelining
),即在同一个TCP
连接里,客户端可以同时发送多个 请求,进一步改进了HTTP
协议的效率。 -
缓存机制
HTTP 1.1
中新增加了E-tag
,If-Unmodified-Since
,If-Match
,If-None-Match
等缓存控制标头来控制缓存失效。 -
断电续传 支持断点续传,通过使用请求头中的
Range
来实现。 -
虚拟网络 使用了虚拟网络,在一台物理服务器上可以存在多个虚拟主机(
Multi-homed Web Servers
),并且它们共享一个IP
地址。 -
新增方法
PUT
、PATCH
、OPTIONS
、DELETE
。
缺点:
-
在传输数据过程中,所有内容都是明文,客户端和服务器端都无法验证对方的身份,无法保证数据的安全性。
-
HTTP/1.1
版本默认允许复用TCP
连接,但是在同一个TCP
连接里,所有数据通信是按次序进行的,服务器通常在处理完一个回应后,才会继续去处理下一个,这样子就会造成队头阻塞。同一个TCP
管道中同一时刻只能处理一个HTTP
请求,也就是说如果当前请求没有处理完,其它的请求都处于阻塞状态,另外浏览器对于同一域名下的并发请求数量都有限制,比如Chrome
中只允许6
个请求并发(这个数量不允许用户配置),也就是说请求数量超过6
个时,多出来的请求只能排队、等待发送。 -
**
Http/1.x
**版本支持Keep-alive
,用此方案来弥补创建多次连接产生的延迟,但是同样会给服务器带来压力,并且的话,对于单文件被不断请求的服务,Keep-alive
会极大影响性能,因为它在文件被请求之后还保持了不必要的连接很长时间。
3.2 长连接
HTTP keep-alive
也称为 HTTP
长连接, 它通过重用一个 TCP
连接来发送/接收多个 HTTP
请求,来减少创建/关闭多个 TCP
连接的开销。我们知道 HTTP
协议采用请求-应答模式,当使用普通模式,即非KeepAlive
模式时,每个请求/应答客户和服务器都要新建一个连接,完成 之后立即断开连接(HTTP
协议为无连接的协议);当使用 Keep-Alive
模式(又称持久连接、连接重用)时,**Keep-Alive
功能使客户端到服 务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive
**功能避免了建立或者重新建立连接。
如图:短连接极大的降低了传输效率
什么是keep-alive
**keep-alive
**是客户端和服务端的一个约定,如果开启 keep-alive
,则服务端在返回 **Response
**后不关闭 TCP
连接;同样的,在接收完响应报文后,客户端也不关闭连接,发送下一个 HTTP
请求时会重用该连接。
为什么要使用keep-alive
**keep-alive
**技术的创建目的,能在多次HTTP之前重用同一个TCP
连接,从而减少创建/关闭多个 TCP
连接的开销(包括响应时间、CPU
资源、减少拥堵等)
如可开启keep-alive
-
在 **
HTTP/1.0
**协议中,默认是关闭的,需要在http
头加入Connection: Keep-Alive
,才能启用Keep-Alive
;Connection: keep-alive
-
**
Http 1.1
**中默认启用Keep-Alive
,如果加入Connection: close
,才关闭Connection: close
长连接优点
- 减少 CPU 及内存的使用,因为不需要经常建立和关闭连接
- 支持管道化的请求及响应模式
- 减少网络堵塞,因为减少了 TCP 请求
- 减少了后续请求的响应时间,因为不需要等待建立 TCP、握手、挥手、关闭 TCP 的过程
- 发生错误时,也可在不关闭连接的情况下进行错误提示
长连接缺点
一个长连接建立后,如果一直保持连接,对服务器来说是多么的浪费资源呀,而且长连接时间的长短,直接影响到服务器的并发数还有就是可能造成队头堵塞(下面有讲),造成信息延迟
如何避免长连接资源浪费?
-
客户端请求头声明:
Connection: close
,本次通信后就关闭连接 -
服务端配置:如 Nginx,设置**
keep-alive_timeout
设置长连接超时时间,keep-alive_requests
**设置长连接请求次数上限 -
系统内核参数设置:
- net.ipv4.tcp_keepalive_time = 60,连接闲置 60 秒后,服务端尝试向客户端发送侦测包,判断 TCP 连接状态,如果没有收到 ack 反馈就在
- net.ipv4.tcp_keepalive_intvl = 10,就在 10 秒后再次尝试发送侦测包,直到收到 ack 反馈,一共会
- net.ipv4.tcp_keepalive_probes = 5,一共会尝试 5 次,要是都没有收到就关闭这个 TCP 连接了
3.3 管道化
管道化/管线化:
**http1.1
**在使用长连接的情况下,建立一个连接通道后,连接上消息的传递类似于
请求1 -> 响应1 -> 请求2 -> 响应2 -> 请求3 -> 响应3
管线化连接的消息就变成了类似这样
请求1 -> 请求2 -> 请求3 -> 响应1 -> 响应2 -> 响应3
管线化是在同一个 TCP 连接里发一个请求后不必等其回来就可以继续发请求出去,这可以减少整体的响应时间,但是服务器还是会按照请求的顺序响应请求,所以如果有许多请求,而前面的请求响应很慢,就产生一个著名的问题队头堵塞
管线化的特点:
- 管线化机制通过持久连接完成,在 http1.1 版本才支持
- 只有 GET 请求和 HEAD 请求才可以进行管线化,而 POST 有所限制
- 初次创建连接时不应启动管线化机制,因为服务器不一定支持 http1.1 版本的协议
- 管线化不会影响响应到来的顺序,如上面的例子所示,响应返回的顺序就是请求的顺序
- 要求客户端和服务端都支持管线化,但并不要求服务端也对响应进行管线化处理,只是要求对于管线化的请求不失败即可
- 由于上面提到的服务端问题,开户管线化很可能并不会带来大幅度的性能提升,而且很多服务端和代理程序对管线化的支持并不好,因为浏览器(Chrome/Firefox)默认并未开启管线化支持
3.4 对头阻塞
对头阻塞
http1.0
协议采用的是请求-应答模式,报文必须是一发一收,就形成了一个先进先出的串行队列,没有轻重缓急的优先级,只有入队的先后顺序,排在最前面的请求最先处理,就导致如果队首的请求耗时过长,后面的请求就只能处于阻塞状态,这就是著名的队头阻塞问题。
如何解决 HTTP
的队头阻塞问题?
-
并发连接
因为一个域名允许分配多个长连接,就相当于增加了任务队列,不至于一个队列里的任务阻塞了其他全部任务。以前在RFC2616中规定过客户端最多只能并发2个连接,但是现实是很多浏览器不按套路出牌,就是遵守这个标准T_T,所以在RFC7230把这个规定取消掉了,现在的浏览器标准中一个域名并发连接可以有6~8个,记住是6~8个,不是6个(Chrome6个/Firefox8个)
-
域名分片
一个域名最多可以并发6~8个,那咱就多来几个域名
比如a.baidu.com,b.baidu.com,c.baidu.com,多准备几个二级域名,当我们访问baidu.com时,可以让不同的资源从不同的二域名中获取,而它们都指向同一台服务器,这样能够并发更多的长连接了
四、HTTP 版本-SPDY
SPDY(读作“SPeeDY”)是Google
开发的基于TCP的会话层协议
主要通过帧、多路复用、请求优先级、HTTP报头压缩、服务器推送以最小化网络延迟,提升网络速度,优化用户的网络使用体验
原理是在SSL层上增加一个SPDY会话层,以在一个TCP连接中实现并发流。通常的HTTP GET和POST格式仍然是一样的,然而SPDY为编码和传输数据设计了一个新的帧格式。因为流是双向的,所以可以在客户端和服务端启动
虽然诞生后很快被所有主流浏览器所采用,并且服务器和代理也提供了支持,但是SPDY核心人员后来都参加到HTTP 2.0开发中去了,自HTTP2.0开发完成就不再支持SPDY协议了,并在Chrome 51中删掉了SPDY的支持
五、HTTP 版本-2.0
5.1 特点
优点:
-
头部压缩:
HTTP 1.1
版本会出现User-Agent
、Cookie
、Accept
、Server
、Range
等字段可能会占用几百甚至几千字节,而Body
却经常只有几十字节,所以导致头部偏重。HTTP 2.0
使用HPACK
算法进行压缩。 -
多路复用: 复用
TCP
连接, 将数据分为多个二进制帧,多个请求和响应的数据帧在同一个TCP
通道进行传输, 且不用按顺序一一对应,这样子解决了队头阻塞的问题。而与此同时,在HTTP2
协议下,浏览器不再有同域名的并发请求数量限制,因此请求排队问题也得到了解决。 -
服务器推送: 允许服务器未经请求,主动向客户端发送资源,即服务器推送。即服务端推送能力。可以让某些资源能够提前到达浏览器,比如对于一个
html
的请求,通过HTTP 2
我们可以同时将相应的js
和css
资源推送到浏览器,省去了后续请求的开销。 -
二进制分帧: 这是一次彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧":头信息帧和数据帧。使用新的二进制协议,不再是纯文本,避免文本歧义,缩小了请求体积
-
请求优先级: 可以设置数据帧的优先级,让服务端先处理重要资源,优化用户体验。
缺点:
-
TCP
以及TCP+TLS
建立连接的延时,HTTP2
使用TCP
协议来传输的,而如果使用HTTPS
的话,还需要TLS
协议进行安全传输,而使用TLS
也需要一个握手过程,在传输数据之前,导致我们花掉3~4
个RTT
-
TCP
的队头阻塞并没有彻底解决。在HTTP2
中,多个请求跑在一个TCP
管道中,但当HTTP2
出现丢包时,整个TCP
都要开始等待重传,那么就会阻塞该TCP
连接中的所有请求
谈一谈你对HTTP 2.0 理解
5.2 头部压缩
头部压缩
HTTP 1.1版本会出现User-Agent、Cookie、Accept、Server、Range 等字段可能会占用几百甚至几千字节,而 Body却经常只有几十字节,所以导致头部偏重。HTTP 2.0使用HPACK算法进行压缩。
从上面看,我们可以看到类似于索引表,每个索引表对应一个值,比如索引为2对应头部中的method头部信息,这样子的话,在传输的时候,不在是传输对应的头部信息了,而是传递索引,对于之前出现过的头部信息,只需要把「索引」(比如1,2,...)传给对方即可,对方拿到索引查表就行了。这种传索引的方式,可以说让请求头字段得到极大程度的精简和复用。其次是对于整数和字符串进行哈夫曼编码。哈夫曼编码的原理就是先将所有出现的字符建立一张索引表,然后让出现次数多的字符对应的索引尽可能短,传输的时候也是传输这样的「索引序列」,可以达到非常高的压缩率。
5.3 多路复用
多路复用
HTTP 1.x 中,如果想并发多个请求,必须使用多个 TCP 链接,且浏览器为了控制资源,还会对单个域名有 6-8个的TCP链接请求限制。
HTTP2中:
- 同域名下所有通信都在单个连接上完成。
- 单个连接可以承载任意数量的双向数据流。
- 数据流以消息的形式发送,而消息又由一个或多个帧组成,多个帧之间可以乱序发送,因为根据帧首部的流标识可以重新组装,也就是Stream ID,流标识符,有了它,接收方就能从乱序的二进制帧中选择ID相同的帧,按照顺序组装成请求/响应报文。
5.4 服务器推送
服务器推送
浏览器发送一个请求,服务器主动向浏览器推送与这个请求相关的资源,这样浏览器就不用发起后续请求。相比较http/1.1的优势
- 推送资源可以由不同页面共享
- 服务器可以按照优先级推送资源
- 客户端可以缓存推送的资源
- 客户端可以拒收推送过来的资源
5.5 二进制分帧
二进制分帧
之前是明文传输,不方便计算机解析,对于回车换行符来说到底是内容还是分隔符,都需要内部状态机去识别,这样子效率低,HTTP/2采用二进制格式,全部传输01串,便于机器解码。这样子一个报文格式就被拆分为一个个二进制帧,用Headers帧存放头部字段,Data帧存放请求体数据。这样子的话,就是一堆乱序的二进制帧,它们不存在先后关系,因此不需要排队等待,解决了HTTP队头阻塞问题。
在客户端与服务器之间,双方都可以互相发送二进制帧,这样子双向传输的序列,称为流,所以HTTP/2中以流来表示一个TCP连接上进行多个数据帧的通信,这就是多路复用概念。
那乱序的二进制帧,是如何组装成对于的报文呢?
- 所谓的乱序,值的是不同ID的Stream是乱序的,对于同一个Stream ID的帧是按顺序传输的。
- 接收方收到二进制帧后,将相同的Stream ID组装成完整的请求报文和响应报文。
- 二进制帧中有一些字段,控制着优先级和流量控制等功能,这样子的话,就可以设置数据帧的优先级,让服务器处理重要资源,优化用户体验。
六、HTTP 版本-3.0
由于HTTP 2.0依赖于TCP,TCP有什么问题那HTTP2就会有什么问题。最主要的还是队头阻塞,在应用层的问题解决了,可是在TCP协议层的队头阻塞还没有解决。
TCP在丢包的时候会进行重传,前面有一个包没收到,就只能把后面的包放到缓冲区,应用层是无法取数据的,也就是说HTTP2的多路复用并行性对于TCP的丢失恢复机制不管用,因此丢失或重新排序的数据都会导致交互挂掉。为了解决这个问题,Google又发明了QUIC协议,并在2018年11月将QUIC正式改名为HTTP 3.0
-
优点:
- 在传输层直接干掉TCP,用UDP替代
- 实现了一套新的拥塞控制算法,彻底解决TCP中队头阻塞的问题
- 实现了类似TCP的流量控制、传输可靠性的功能。虽然UDP不提供可靠性的传输,但QUIC在UDP的基础之上增加了一层来保证数据可靠性传输。它提供了数据包重传、拥塞控制以及其他一些TCP中存在的特性
- 实现了快速握手功能。由于QUIC是基于UDP的,所以QUIC可以实现使用0-RTT或者1-RTT来建立连接,这意味着QUIC可以用最快的速度来发送和接收数据。
- 集成了TLS加密功能。目前QUIC使用的是TLS1.3