万维网30 周年了

今天是2019年3月12日,是万维网诞生 30周年的纪念日,搜索引擎巨头谷歌为此在首页换上了互联网发明的Logo以此来纪念万维网诞生 30周年。

此外,今天早上,著名的开源web 服务器厂商 nginx 宣布被 F5 收购。我觉得今天可以和大家分享下互联网的那些历史。

我们今天之所以可以在网络上畅游,都要感谢一个人,他就是被誉为互联网之父的英国计算机科学家—蒂姆·伯纳斯-李

1980年6月至12月间,伯纳斯-李在日内瓦的CERN(欧洲核子研究组织)担任独立承包人,在那段时间里,他提出了一个构想:创建一个以超文本系统为基础的项目,其目的是方便研究人员分享及更新信息。

世界上第一个网站在CERN搭建,网站在1991年8月6日上线,Info.cern.ch是世界上第一个网站及网站服务器。网站在一台位于CERN的NeXT计算机上运作。

伯纳斯-李发明的超文本传输控制协议,就是我们今天熟悉的 HTTP 协议。目前 HTTP 协议的最新版本是 HTTP/2,HTTP 协议是互联网的基础协议。没有 HTTP 协议就没有我们今天的互联网。

HTTP 协议采用 BS 架构,也就是浏览器到服务器的架构

客户端通过浏览器发送 HTTP 请求给服务器,服务器经过解析响应客户端的请求。

HTTP 是基于 TCP/IP 协议的应用层协议。在OSI 七层模型中他在最上层,它并不涉及数据包(packet)传输,主要规定了客户端和服务器之间的通信格式,HTTP 协议默认使用80端口。

HTTP 协议最早的一个版本是1991发布的 HTTP/0.9,这个版本只有一个命令,GET。通过 GET 你可以获取服务器的资源。比如请求服务器根目录下的 index.html 文件

1
GET /index.html

则服务器会返回给客户端 index.html 的内容并通过客户端浏览器进行渲染和解析 html 标签。这个版本的协议规定,服务器只能回应HTML格式的字符串,不能回应别的格式。也就是说今天的图像、视频等多媒体资源在 HTTP/0.9这个版本上是无法进行传输的。

1
2
3
<html>
<body>Hello World</body>
</html>

1996年5月,HTTP/1.0 版本发布,增加了POST命令和HEAD命令,丰富了浏览器与服务器的互动手段,这个版本通过HTTP协议任何格式的内容都可以发送。包括传输文字,图像、视频、文件。这为互联网的大发展奠定了基础。

HTTP/1.0 除了增加了请求方法以及对发送文件的支持之外,还增加了格式的改变。除了数据部分,每次通信都必须包括头信息(HTTP header),用来描述一些元数据。另外还增加了状态码、多字符集支持、多部分发送(multi-part type)、权限(authorization)、缓存(cache)、内容编码(content encoding)等等。

一个正常的 HTTP 请求和响应包括请求的网址、请求方法、状态码、HTTP协议版本、请求头和响应头。

例如下图所示,请求google的 HTTP 消息头所示

在字符的编码问题上,HTTP/1.0版规定,头信息必须是 ASCII 码,后面的数据可以是任何格式。因此,服务器回应的时候,必须告诉客户端,数据是什么格式,这就是Content-Type字段的作用。

1
2
3
4
5
6
7
8
9
text/html
text/css
image/jpeg
image/png
image/svg+xml
audio/mp4
video/mp4
application/javascript
application/pdf

这些数据类型总称为MIME type,每个值包括一级类型和二级类型,之间用斜杠分隔。

此外,由于 HTTP/1.0 还可以对数据进行压缩后传输,通过Content-Encoding字段说明数据的压缩方法

1
Content-Encoding: gzip

表示使用 gzip 压缩数据

HTTP/1.0 版也并不是完美的,他的主要缺点是,每一次建立TCP连接只能发送一个请求。发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接。如果多次请求,势必就会造成频繁的对服务器进行请求而对服务器产生较大的资源损耗。

为了解决这个问题,有些浏览器在请求时,用了一个非标准的Connection字段。

1
Connection: keep-alive

这个字段要求服务器不要关闭TCP连接,以便其他请求复用。服务器同样回应这个字段。但是这个并不是一个统一的标准。

1997年1月,HTTP/1.1 版本发布,这个版本只比 1.0 版本晚了半年。它进一步完善了 HTTP 协议,一直用到了今天,直到现在还是最流行的版本。

这个版本最大的变化就是将持久化连接加入了 HTTP 标准,即TCP连接默认不关闭,可以被多个请求复用,不用声明Connection: keep-alive

客户端和服务器发现对方一段时间没有活动,就可以主动关闭连接。不过,规范的做法是,客户端在最后一个请求时,发送Connection: close,明确要求服务器关闭TCP连接。

此外,HTTP/1.1版还新增了许多方法,例如:PUTPATCHHEADOPTIONSDELETE

另外,客户端请求的头信息新增了Host字段,Content-Length 字段、管道机制等新特性。

HTTP1.1版虽然允许复用TCP连接,但是同一个TCP连接里面,所有的数据通信是按次序进行的。服务器只有处理完一个回应,才会进行下一个回应。要是前面的回应特别慢,后面就会有许多请求排队等着。这称为队头堵塞。

为了解决这个问题,2009年,谷歌公开了自行研发的 SPDY 协议,这个协议在Chrome浏览器上证明可行以后,就被当作 HTTP/2 的基础,主要特性都在 HTTP/2 之中得到继承。

2015年,HTTP/2 发布。它不叫 HTTP/2.0,是因为标准委员会不打算再发布子版本了,下一个新版本将是 HTTP/3。

HTTP/2 增加了二进制分帧、多路复用、服务器推送(server push)、头部压缩等特性

HTTP/2 采用二进制格式传输数据,而非 HTTP 1.x 的文本格式,二进制协议解析起来更高效。 HTTP / 1 的请求和响应报文,都是由起始行,首部和实体正文(可选)组成,各部分之间以文本换行符分隔。HTTP/2 将请求和响应数据分割为更小的帧,并且它们采用二进制编码。

多路复用,代替原来的序列和阻塞机制。所有就是请求的都是通过一个 TCP连接并发完成。 HTTP 1.x 中,如果想并发多个请求,必须使用多个 TCP 链接,且浏览器为了控制资源,还会对单个域名有 6-8个的TCP链接请求限制。

在 HTTP/2 中,有了二进制分帧之后,HTTP /2 不再依赖 TCP 链接去实现多流并行了,在 HTTP/2中:

  • 同域名下所有通信都在单个连接上完成。
  • 单个连接可以承载任意数量的双向数据流。
  • 数据流以消息的形式发送,而消息又由一个或多个帧组成,多个帧之间可以乱序发送,因为根据帧首部的流标识可以重新组装。

这一特性,使性能有了极大提升:

  • 同个域名只需要占用一个 TCP 连接,消除了因多个 TCP 连接而带来的延时和内存消耗。
  • 单个连接上可以并行交错的请求和响应,之间互不干扰。
  • 在HTTP/2中,每个请求都可以带一个31bit的优先值,0表示最高优先级, 数值越大优先级越低。有了这个优先值,客户端和服务器就可以在处理不同的流时采取不同的策略,以最优的方式发送流、消息和帧。

服务端可以在发送页面HTML时主动推送其它资源,而不用等到浏览器解析到相应位置,发起请求再响应。例如服务端可以主动把JS和CSS文件推送给客户端,而不需要客户端解析HTML时再发送这些请求。

服务端可以主动推送,客户端也有权利选择是否接收。如果服务端推送的资源已经被浏览器缓存过,浏览器可以通过发送RST_STREAM帧来拒收。主动推送也遵守同源策略,服务器不会随便推送第三方资源给客户端。

HTTP/3 是即将到来的第三个主要版本的HTTP协议。在HTTP/3中,将弃用TCP协议,改为使用基于UDP协议的QUIC协议实现。QUIC 协议是 google 开发的一套协议,IETF 中的 QUIC 工作组致力于创建 QUIC 传输协议。 QUIC 是基于 UDP 实现的协议,是用来替换 TCP 的。QUIC 协议最初是由Google发起的项目,后面慢慢成为了 HTTP/2-encrypted-over-UDP 协议。

本文原创发布于 CSDN https://mp.weixin.qq.com/s/YG992ga-BXlxXB6i-k0t8g