# HTTP 的发展历程
前言
了解http的发展历史,可以帮助我们更好的理解这项协议的内容。http协议自诞生到现在为止,共有四个版本,下面我们就来看看每个版本都有哪些作用,以及它是如何一步一步的演化成现在的协议版本的。
# HTTP/0.9
HTTP/0.9是最早的一个协议版本,它的内容非常简单:
- 只有一个命令 GET
- 没有描述实体内容的头部信息(headers)
- 服务端返回的内容是html格式的字符串
- 每个事务结束就释放连接。例如,客户端请求服务端的一个网页,服务端返回后,会关闭这次TCP连接。
举个例子,http/0.9的工作过程大概如下:
- 客户端发送请求:
GET /index.html
- 服务端返回内容:
<html>...</html>
- 关闭TCP连接,结束。
# HTTP/1.0
由于互联网的发展,http/0.9已经满足不了需求了,于是在它的基础上,http/1.0协议主要增加了以下内容:
- 增加了请求头与响应头
- 响应对象支持多种数据格式
- 增加了状态码
- 支持多种方法,比如
POST
,HEAD
等 - 支持长连接(默认还是短连接)
- 缓存机制(
Pragma
首部字段等)、身份验证、多字符集等
http/1.0增加的内容,很多我们现在都还在沿用。
# HTTP/1.1
http/1.1 是目前沿用最广泛的一个版本,它相对与1.0,主要增加了以下内容:
默认使用长连接
我们经常看到这个header字段:
Connection: Keep-Alive
,这是在http/1.1中默认开启的一个功能,它可以在每次请求完毕以后,依旧保持着这个TCP连接,这就极大的避免了1.0及以前版本的短连接方式带来的问题:重复创建TCP连接。我们知道,创建TCP需要客户端与服务端进行三次握手,如果每次请求都要重新创建新的TCP连接的话,那么就会增加很多的消耗和延迟,影响效率。Pipeline
Pipeline的技术可以让浏览器可以同时向服务器发送几个请求,收到请求的服务器必须按照请求的顺序来发送响应。这个看起来似乎很美好,但是实践的时候却会出现很多问题,比如:- pipelining只能适用于http1.1,一般来说,支持http1.1的server都要求支持pipelining
- 只有幂等的请求(GET,HEAD)能使用pipelining,非幂等请求比如POST不能使用,因为请求之间可能会存在先后依赖关系
- head of line blocking并没有完全得到解决,server的response还是要求依次返回,遵循FIFO(first in first out)原则。也就是说如果请求1的response没有回来,2,3,4,5的response也不会被送回来
- 绝大部分的http代理服务器不支持pipelining
- 和不支持pipelining的老服务器协商有问题
- 可能会导致新的Front of queue blocking问题
所以浏览器大多数要么不支持,要么是默认关闭这个功能的。
支持范围请求
增加了请求头
range
来标识需要请求的资源的范围,和状态码206(Partial Content)
来标识这次范围请求的成功状态。这很大程度上节省了带宽。试想一个很大的文件,我们下载到一半以后因为一些原因网络断开,这时候再次下载的时候,我们不希望还是从头下载。理想情况下,应该是从上次停掉的地方接着下载,这样才不会浪费。增加了host字段来提供虚拟主机的功能
请求头新增了
host
字段来表示标识请求的目标主机。我们知道,一台物理主机上可以有多个虚拟主机,比如我有一个阿里云的服务器,我在上面部署了一个商城的服务,一个新闻的服务,当我从浏览器上访问的时候,实际上通过DNS解析后,最终都会通过IP地址找到我的这台阿里云服务器,但是具体找的是哪一个服务,我们可以通过host
字段来判断。如果没有host
字段或者host
字段包含多个值的时候,服务器一般会返回400的错误码。更强大的缓存处理和更丰富的错误处理
提供了
E-Tag
、Cache-Control
来进行更精确的缓存的控制;新增了很多状态码来表示可能出现的http错误信息等。
# HTTP/2.0
关于http2的介绍,可以具体的参考知乎上的这个讨论:知乎-HTTP/2 相比 1.0 有哪些重大改进。这里我只给出一个大概的介绍,它相对于1.1,做出了如下的改进:
- 多路复用
多路复用允许同时通过单一的 HTTP/2 连接发起多重的请求-响应消息。
- 二进制分帧
HTTP/2在应用层(HTTP/2)和传输层(TCP or UDP)之间增加一个二进制分帧层。在二进制分帧层中, HTTP/2 会将所有传输的信息分割为更小的消息和帧(frame),并对它们采用二进制格式的编码 ,其中 HTTP1.x 的首部信息会被封装到 HEADER frame,而相应的 Request Body 则封装到 DATA frame 里面。
- 首部压缩
使用HPACK算法对首部字段进行压缩,减少了传输的数据量。
- 服务端推送
服务端推送是一种在客户端请求之前发送数据的机制。在 HTTP/2 中,服务器可以对客户端的一个请求发送多个响应。Server Push 让 HTTP1.x 时代使用内嵌资源的优化手段变得没有意义;如果一个页面的请求是由你发起的,服务器很可能会响应主页内容、logo、js脚本、样式表等,因为它知道客户端会用到这些东西。这相当于在一个 HTML 文档内集合了所有的资源,不过与之相比,服务器推送还有一个很大的优势:可以缓存!也让在遵循同源的情况下,不同页面之间可以共享缓存资源成为可能。
# 参考资料
HTTP缓存 →