Intro to HTTP/1

前言
在 HTTP 发布正式版之前,HTTP 的版本号被定位在 0.9 以区分后来的版本。HTTP/0.9 极其简单:请求由单行指令构成,以唯一可用方法 GET 开头,其后跟目标资源的路径。
GET /mypage.html
请求的响应不包含 HTTP 头,且只支持传输 HTML 类型的文档,无法传输其他类型的文件;也没有状态码或错误代码:一旦出现问题,一个特殊的包含问题描述信息的 HTML 文件将被发回,供人们查看。
HTTP/1.0
由于 HTTP/0.9 协议的应用十分有限,HTTP/1.0 版本发布丰富了 HTTP 协议的内容,增加了 HTTP 的应用场景。HTTP/1.0 的改进具体如下:
- 除了支持 GET 请求类型外,还支持 POST 和 HEAD 请求。
- 为请求和回应都增加了头信息(HTTP header)。
- 为头信息添加了
Content-Type
字段,可以传输任何类型的内容,包括文字、图像、视频等。 - 增加了状态码、权限、缓存(Expires 等)、内容编码(Content-Encoding)等功能。
请求和回应格式
- 请求格式
GET /myimage.gif HTTP/1.0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5)
Accept: */*
- 回应格式
HTTP/1.0 200 OK
Content-Type: text/gif
Content-Length: 137582
Expires: Thu, 05 Dec 1997 16:00:00 GMT
Last-Modified: Wed, 5 August 1996 15:55:28 GMT
Server: Apache 0.84
(这里是图片内容)
在上述的请求和响应的头信息中有几个头信息字段,例如 Content-Type、Last-Modified 等,这些字段都包含特定的含义,用来描述一些元数据。但本篇并不会对这些字段做过多的解释,后面会单独有一章详细介绍这些字段,如果这些字段让你感到困惑,可以先百度查询。
HTTP/1.0 的缺点
HTTP/1.0 版的主要缺点是,每个 TCP 连接只能发送一个请求。发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接。
TCP 连接的新建成本很高,因为需要客户端和服务器三次握手,并且开始时发送速率较慢(slow start)。所以,HTTP 1.0 版本的性能比较差。随着网页加载的外部资源越来越多,这个问题就愈发突出了。
为了解决这个问题,有些浏览器在请求时,用了一个非标准的Connection: keep-alive
字段。这个字段要求服务器不要关闭 TCP 连接,以便其他请求复用。服务器同样回应这个字段。但是,这不是标准字段,不同实现的行为可能不一致,因此不是根本的解决办法。
HTTP/1.1
HTTP/1.1 版本发布,只比 1.0 版本晚了半年。它进一步完善了 HTTP 协议,一直用到了 20 年后的今天,直到现在还是最流行的版本。
长连接
HTTP/1.1 版的最大变化,就是引入了持久连接(persistent connection),持久连接解决的核心问题是一定时间内,同一域名多次请求数据,只建立一次 HTTP 请求,其他请求可复用每一次建立的连接通道,以达到提高请求效率的问题。这里面所说的一定时间是可以配置的,不管你用的是 Apache 还是 nginx。
因为 TCP 连接长时间不关闭,服务器必须在内存里保存它的状态,这就占用了服务器的资源。如果有大量的空闲长连接只连不发,就会很快耗尽服务器的资源,导致服务器无法为真正有需要的用户提供服务。所以当客户端和服务器发现对方一段时间没有活动,就可以主动关闭连接。不过,规范的做法是,客户端在最后一个请求时,发送 Connection: close
,明确要求服务器关闭 TCP 连接。

通过上图可以看出,在客户端和服务器需要多次传输时,长链接相比与短链接的效率要高很多。
目前,对于同一个域名,大多数浏览器允许同时建立 6 个持久连接。

由上图可知 HTTP/1.1 客户端和服务端建立链接的特点如下:
- 每个连接都会产生完整的 TCP 握手
- 每个连接都会产生 TLS 握手开销(最好的情况,已恢复)
- 每个连接占用服务器/代理资源(内存,CPU 等)
- 每个连接都与其他连接竞争(拥塞控制中断)
Keep-Alive,他解决了多次连接的问题,但是依然有两个效率上的问题:
-
串行的文件传输。当请求 a 文件时,b 文件只能等待,等待 a 连接到服务器、服务器处理文件、服务器返回文件,这三个步骤。我们假设这三步用时都是 1 秒,那么 a 文件用时为 3 秒,b 文件传输完成用时为 6 秒,依此类推。(注:此项计算有一个前提条件,就是浏览器和服务器是单通道传输)
-
连接数过多。我们假设 Apache 设置了最大并发数为 300,因为浏览器限制,浏览器发起的最大请求数为 6,也就是服务器能承载的最高并发为 50,当第 51 个人访问时,就需要等待前面某个请求处理完成。