HTTP1:HTTP性能优化

HTTP是浏览器中最重要使⽤最多的协议,是浏览器和服 务器之间的通信语⾔,也是互联⽹的基⽯。

超⽂本传输协议HTTP/0.9

HTTP/0.9是于1991年提出的,主要⽤于学术交流,需求很简单⸺ ⽤来在⽹络之间传递HTML超⽂本的内容,所以被称为超⽂本传输协议。它的实现也很简单,采 ⽤了基于请求响应的模式,从客⼾端发出请求,服务器返回数据。

HTTP/0.9的⼀个完整的请求流程

  • 因为HTTP都是基于TCP协议的,所以客⼾端先要根据IP地址、端⼝和服务器建⽴TCP连接,⽽建⽴连接 的过程就是TCP协议三次握⼿的过程。
  • 建⽴好连接之后,会发送⼀个GET请求⾏的信息,如GET /index.html⽤来获取index.html。
  • 服务器接收请求信息之后,读取对应的HTML⽂件,并将数据以ASCII字符流返回给客⼾端。
  • HTML⽂档传输完成后,断开连接。


总的来说,当时的需求很简单,就是⽤来传输体积很⼩的HTML⽂件,而没有其他的操作,所以HTTP/0.9的实现有以下三个特点。

  • 只有⼀个请求⾏,并没有HTTP请求头和请求体,因为只需要⼀个请求⾏就可以完整表达客⼾端 的需求了。
  • 服务器也没有返回头信息,这是因为服务器端并不需要告诉客⼾端太多信息,只需要返回数据就 可以了。
  • 返回的⽂件内容是以ASCII字符流来传输的,因为都是HTML格式的⽂件,所以使⽤ASCII字节码 来传输是最合适的

被浏览器推动的HTTP/1.0

⾸先在浏览器中展⽰的不单是HTML⽂件了,还包括了JavaScript、CSS、图⽚、⾳频、视频等不同类型的 ⽂件。因此⽀持多种类型的⽂件下载是HTTP/1.0的⼀个核⼼诉求,⽽且⽂件格式不仅仅局限于ASCII编码, 还有很多其他类型编码的⽂件。

实现多种类型⽂件的下载

HTTP/1.0引⼊了请求头和响应头,它们都是以为Key-Value形式保存的,在HTTP发送请求时,会带上请求 头信息,服务器返回数据时,会先返回响应头信息。

要⽀持多种类型的⽂件,就需要解决以下⼏个问题。

  • ⾸先,浏览器需要知道服务器返回的数据是什么类型的,然后浏览器才能根据不同的数据类型做针对性的 处理。
  • 为了减轻传输性 能,服务器会对数据进⾏压缩后再传输,所以浏览器需要知道服务器压缩的⽅法。
  • 服务器需要对不同的地区提供不同的 语⾔版本,这就需要浏览器告诉服务器它想要什么语⾔版本的⻚⾯。
  • 为了能够准确地读取⽂ 件,浏览器需要知道⽂件的编码类型。

基于以上问题,HTTP/1.0的⽅案是通过请求头和响应头来进⾏协商,在发起请求时候会通过HTTP请求头告 诉服务器它期待服务器返回什么类型的⽂件、采取什么形式的压缩、提供什么语⾔的⽂件以及⽂件的具体编 码。最终发送出来的请求头内容如下:

accept: text/html
accept-encoding: gzip, deflate, br
accept-Charset: ISO-8859-1,utf-8
accept-language: zh-CN,zh

第一行表示服务器返回的是html类型的文件;

第二行表示期望服务器可以采取gzip及其他两种中的一种进行压缩;

第三行表示期望返回的文件编码是UTF-8或者另外一种;

第四行是期望页面的优先语言是中文。


服务器接收到浏览器发送过来的请求头信息之后,会根据请求头的信息来准备响应数据。

不过有时候会有⼀ 些意外情况发⽣,⽐如浏览器请求的压缩类型是gzip,但是服务器不⽀持gzip,只⽀持br压缩,那么它会通 过响应头中的content-encoding字段告诉浏览器最终的压缩类型,也就是说最终浏览器需要根据响应头的 信息来处理数据。

content-encoding: br
content-type: text/html; charset=UTF-8

HTTP/1.0除了对多⽂件提供良好的⽀持外,还依据当时实际的需求引⼊了很多其他的特性,这些特性都是 通过请求头和响应头来实现的。

  • 有的请求服务器可能⽆法处理,或者处理出错,这时候就需要告诉浏览器服务器最终处理该请求的情况, 这就引⼊了状态码。状态码是通过响应⾏的⽅式来通知浏览器的。
  • 为了减轻服务器的压⼒,在HTTP/1.0中提供了Cache机制,⽤来缓存已经下载过的数据。
  • 服务器需要统计客⼾端的基础信息,⽐如Windows和macOS的⽤⼾数量分别是多少,所以HTTP/1.0的请 求头中还加⼊了⽤⼾代理的字段。

缝缝补补的HTTP/1.1

改进持久连接

HTTP/1.0每进⾏⼀次HTTP通信,都需要经历建⽴TCP连接、传输HTTP数据和断开TCP连接三个阶段

如 果在下载每个⽂件的时候,都需要经历建⽴TCP连接、传输数据和断开连接这样的步骤,⽆疑会增加⼤量⽆ 谓的开销。

为了解决这个问题,HTTP/1.1中增加了持久连接的⽅法,它的特点是在⼀个TCP连接上可以传输多个HTTP 请求,只要浏览器或者服务器没有明确断开连接,那么该TCP连接会⼀直保持。

HTTP的持久连接可以有效减少TCP建⽴连接和断开连接的次数,这样的好处是减少了服 务器额外的负担,并提升整体HTTP的请求时⻓

如果不想要采⽤持久连接,可以在HTTP请求头中加上Connection: close。⽬前浏览器中对于同⼀个域名,默 认允许同时建⽴6个TCP持久连接。


不成熟的HTTP管线化

持久连接虽然能减少TCP的建⽴和断开次数,但是它需要等待前⾯的请求返回之后,才能进⾏下⼀次请求

如果TCP通道中的某个请求因为某些原因没有及时返回,那么就会阻塞后⾯的所有请求,这就是著名的队头阻塞的问题

HTTP/1.1中的管线化是指将多个HTTP请求整批 提交给服务器的技术,虽然可以整批发送请求,不过服务器依然需要根据请求顺序来回复浏览器的请求。但是由于各种原因,它们最终都放弃了管线化技术。


提供虚拟主机的⽀持

在HTTP/1.0中,每个域名绑定了⼀个唯⼀的IP地址,因此⼀个服务器只能⽀持⼀个域名。

但是随着虚拟主 机技术的发展,需要实现在⼀台物理主机上绑定多个虚拟主机,每个虚拟主机都有⾃⼰的单独的域名,这些 单独的域名都共⽤同⼀个IP地址。

因此,HTTP/1.1的请求头中增加了Host字段,⽤来表⽰当前的域名地址,这样服务器就可以根据不同的Host值做不同的处理。


对动态⽣成的内容提供了完美⽀持

在设计HTTP/1.0时,需要在响应头中设置完整的数据⼤⼩,如Content-Length: 901,这样浏览器就可 以根据设置的数据⼤⼩来接收数据。

不过随着服务器端的技术发展,很多⻚⾯的内容都是动态⽣成的,因此 在传输数据之前并不知道最终的数据⼤⼩,这就导致了浏览器不知道何时会接收完所有的⽂件数据。

HTTP/1.1通过引⼊Chunk transfer机制来解决这个问题,服务器会将数据分割成若⼲个任意⼤⼩的数据 块,每个数据块发送时会附上上个数据块的⻓度,最后使⽤⼀个零⻓度的块作为发送数据完成的标志。这样 就提供了对动态内容的⽀持。