HTTP/1.0
- 无状态:服务器不跟踪不记录请求过的状态
- 无连接:浏览器每次请求都需要建立tcp连接
浏览器的每次请求都需要与服务器建立一个TCP连接,服务器处理完成后立马断开TCP连接(无连接),服务器不跟踪每个客户端也不记录过去的请求(无状态),这种无状态性可以借助cookie/session机制来做身份认证和状态记录。
无连接导致缺点
- 无法复用连接,每次发送请求都需要进行一次TCP连接释放,这导致网络利用率低
- 队头阻塞。由于
HTTP/1.0规定下一个请求在前一个响应到达前不能发送,假设前一个请求响应一直不到达,那么下一个请求就不发送,导致阻塞后面的请求
HTTP/1.1
- 在缓存方面,
http1.0只能使用expires,if-modified-since来进行缓存判断,http1.1则增加了cache-control,e-tag,if-none-match等更多缓存头来控制缓存 - 优化了带宽利用,
http1.0客户端可能只需要某个对象的一部分,而服务端则将整个对象送过来了,到了http1.1,请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206。 - 错误通知的管理,http1.1中新增了24个错误状态响应码,如
409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。 - Host头处理,在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。
- 长连接,http1.1中默认开启
Connection:keep-alive,可以在同一条tcp连接上进行多个请求和响应,减少了每次请求都建立和关闭连接的消耗和延迟
HTTP/2.0
前面说到的http1.1还是有些缺点:
-
队头阻塞:tcp上发的请求得等前一个请求响应返回了,下一个请求才能发出去,后续的请求都得排队等候,虽然http1.1管线化可以支持请求并发,这个请求并发确实依赖于创建多个tcp连接,成本很高,浏览器很难实现
-
HTTP/1.X版本是采用文本格式,首部未压缩,http1.1的header带有大量信息,每次都要重复发送
二进制分帧层
HTTP2性能提升的核心就在于二进制分帧层。HTTP2是二进制协议,他采用二进制格式传输数据而不是1.x的文本格式。
1.1响应是文本格式,而2.0把响应划分成了两个帧,图中的HEADERS(首部)和DATA(消息负载) 是帧的类型。也就是说一条HTTP响应,划分成了两个帧来传输,并且采用二进制来编码。
这里我们来提三个概念。
- 流(Stream):已建立的TCP连接上的双向字节流,可以承载一个或多个消息。
- 消息(Message):一个完整的HTTP请求或响应,由一个或多个帧组成。特定消息的帧在同一个流上发送,这意味着一个HTTP请求或响应只能在一个流上发送。
- 帧(Frame):通信的基本单位。
一个TCP连接上可以有任意数量的流。
多路复用
上面提到HTTP/1.1的线头阻塞和多个TCP连接的问题,HTTP2的多路复用完美解决。多路复用是这样实现多路复用的:http2.0创建一个tcp连接,一个连接上面可以有任意多个流,消息分割成一个或多个帧在流里面,帧传输过去后再进行重组,形成一个完整的请求或响应。但是还是会有请求排队的情况,因为服务器的处理请求的能力不是无止境的,流控制会管理数据的传输,当请求太多时,它会减少或停止请求的发送,免得接收方不堪重负
头部压缩
在1.X版本中,首部用文本格式传输,通常会给每个传输增加500-800字节的开销,现在一个网站上百个请求已经是常态了,每个请求的头部的一些字段都是相同的,例如cookie,user-agent等,所以http2.0会用HPACK压缩格式来压缩头部,头部压缩需要在浏览器和服务器端之间:
- 维护一份相同的静态字典,包含常见的头部名称,以及常见的头部名称和值的组合
- 维护一份相同的动态字典,可以动态的添加内容
- 通过静态Huffman编码对传输的首部字段进行编码
所以我们在传输首部字段的时候,例如要传输method:GET,那我们只需要传输静态字典里面method:GET对应的索引值就可以了,一个字节搞定。
像user-agent、cookie这种静态字典里面只有首部名称而没有值的首部,第一次传输需要user-agent在静态字典中的索引以及他的值,值会采用静态Huffman编码来减小体积。第一次传输过user-agent 之后呢,浏览器和服务器端就会把它添加到自己的动态字典中。后续传输就可以传输索引了,一个字节搞定。
服务器端推送
服务器端推送使得服务器可以预测客户端需要的资源,主动推送到客户端。
例如:客户端请求index.html,服务器端能够额外推送script.js和style.css。 实现原理就是客户端发出页面请求时,服务器端能够分析这个页面所依赖的其他资源,主动推送到客户端的缓存,当客户端收到原始网页的请求时,它需要的资源已经位于缓存。
总结
HTTP 1.0
- 无状态
- 无连接
HTTP 1.1
- 长连接
- 增加缓存处理(cache-control,e-tag,If-none-match等)
- 增加host头域
- 增加range头域,支持断点重传,不用一整个对象返回,只返回需要的部分,返回206
- 新增错误响应状态码
HTTP 2.0
- 二进制分帧
- 多路复用
- 头部压缩
- 服务器端推送