应用层协议之 HTTP 超文本传输协议手册
后知后觉 现有 1 评论

HTTP(HyperText Transfer Protocol,超文本传输协议)是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP 是 WWW(World Wide Web,全球广域网)万维网的数据通信基础。

HTTP 协议简介

起源

设计 HTTP 协议最初的目的是为了提供一种发布和接收 HTML 页面的方法,现在已然是短连接通信的事实工业标准。通过 HTTP 或者 HTTPS 协议请求的资源由 URI (Uniform Resource Identifiers,统一资源标识符)来标识。

HTTP 协议是由 蒂姆·伯纳斯-李(Tim Berners-Lee)于 1989 年在 CERN (European Organization
for Nuclear Research,欧洲核子研究组织)所发起。HTTP 的标准制定由 W3C (World Wide Web Consortium,万维网协会)和 IETF (Internet Engineering Task Force,互联网工程任务组)进行协调,最终发布了一系列的 RFC(Request For Comments,请求评论)可以理解为“协议规范”。

演进

超文本传输协议已经演化出了很多版本,它们中的大部分都是向下兼容的。在 RFC 2145 中描述了 HTTP 版本号的用法。客户端在请求的开始告诉服务器它采用的协议版本号,而后者则在响应中采用相同或者更早的协议版本。

版本历史卷轴

HTTP/0.9

这是 HTTP 于 1991 年推出的首个可用协议标准,此版本协议内容很简单,支持的方法更是廖少,仅支持 GET 一种方法,使用 80 端口,服务器仅可响应 HTML 格式的数据,发送完毕后关闭 TCP 连接。

序号方法引入版本描述
1GETHTTP/0.9请求指定的页面,并返回页面内容
实际上 HTTP 协议问世时,并未制定版本号,HTTP/0.9 是后来为了方便区分才给定义的。

HTTP/1.x

在 1996 年 5 月 HTTP 协议迎来一次重大升级:HTTP/1.0 发布(详见 RFC1945)。首先传输内容不再受限于 HTML,图片、二进制文件等也可传输,这为互联网的大发展奠定了基础。其次方法不再仅有 GET 方法,额外支持了 POST 和 HEAD 方法,增加了于浏览器间的互动手段。

序号方法引入版本描述
2HEADHTTP/1.0与 GET 相同,但只返回 HTTP 报头,返回的响应并不包含页面内容。
3POSTHTTP/1.0向指定的资源提交要被处理的数据(提交表单,上传文件),数据将被包裹在请求体中。

在 1999 年 6 月,HTTP/1.1 发布(详见 RFC2616),【实际上 HTTP/1.0 发布后半年的 1997 年 1 月,HTTP/1.1 草案就已提交】进一步完善了 HTTP 协议,此版本一直沿用至今,截至目前仍是互联网中主流版本。

小贴士:在此版本中添加了很多特性,解决了 HTTP/1.0 中的缺点,以下选择部分重点特性进行说明。

持久连接,在 HTTP/1.0 中每个请求都会发起一个 TCP 连接,发送完成后立即关闭,因为 TCP 协议复杂的握手流程导致每个连接的新建成本很高(主要指延迟),在 HTTP/1.1 中,TCP 连接默认不中断,可被多个请求复用,客户端和服务端发现对方长时间无活动后才会关闭连接,不过,规范的做法是:客户端在最后一个请求时,发送 Connection: close 标识,要求服务器关闭连接,这个特性极大提高了连接的利用率,但是随之而来的问题就是会明显提高服务端的资源占用,部分请求即使请求并不活跃也会占用一个或多个 TCP 连接。

内容长度,因为持久连接特性的加入,引发了一个新问题:就是一个连接被多个请求复用,客户端无法确认当前的数据属于哪一个请求,因此引入了 Content-Length 字段,用来声明本次回应的数据长度,以区分不同的请求内容。

分块传输,使用内容长度字段的前提条件是,服务器返回响应之前,必须知道响应的数据长度。因此对于一些很耗时的动态操作来说,这意味着服务器要等到所有操作完成,才能发送数据,显然这样的效率不高。于是引入了分块传输编码 Transfer-Encoding: chunked 字段,产生一块数据,就发送一块(即“数据流模式”),在 HTTP/1.1 中可以不指定 Content-Length 字段,只要请求或回应的头信息有分块传输编码字段,就表明接下来的响应将由数量未定的数据块组成,在每个非空的数据块之前,会有一个16进制的数值,表示这个块的长度,最后使用一个大小为零的块表示本次响应数据发送完毕。

队头阻塞,HTTP/1.1 的缺点也因为 TCP 连接复用导致同一个连接里面,所有的数据通信是按次序进行的。服务器只有处理完一个回应,才会进行下一个回应。如果前面的回应特别慢,后面就会有许多请求排队等着,这称为"队头堵塞"(Head-of-line blocking)。

主机字段,客户端请求的头信息新增了主机 Host: example.com 字段,用来指定请求服务器的域名,有了主机字段,就可以将请求发往同一台服务器上的不同网站,为虚拟主机的兴起打下了基础。

此外还引入了更多的请求方法:

序号方法引入版本描述
4PUTHTTP/1.1向指定资源位置上传其最新内容。
5DELETEHTTP/1.1请求服务端删除指定资源。
6CONNECTHTTP/1.1把请求连接转换到透明的 TCP/IP 通道,通常用于SSL加密服务器的链接。
7OPTIONSHTTP/1.1返回服务器支持的 HTTP 方法。
8TRACEHTTP/1.1回显服务器收到的请求,用于诊断和测试。
小贴士:至此,HTTP/1.1 中定义的八种方法(也称为动作)介绍完毕,这些新增的方法扩充了操作指定资源的方式,完善了使用的体验。方法名称是区分大小写的。当某个请求所针对的资源不支持对应的请求方法的时候,服务器应当返回状态码 405 (Method Not Allowed) ,当服务器不认识或者不支持对应的请求方法的时候,应当返回状态码 501 (Not Implemented) 。一般情况下服务器至少应该实现 GET 和 HEAD 方法,其他方法皆为可选。此外,除了上述方法,特定的 HTTP 服务器还能够扩展自定义的方法。例如:在 2010 年引入的 PATCH 方法(详见 RFC5789)用于将局部修改应用到资源。

HTTP/2

在 2014 年 12 月,互联网工程任务组的 HTTPBIS (Hypertext Transfer Protocol Bis)工作组将 HTTP/2 标准提议递交至 IESG 进行讨论,于 2015 年 2 月 17 日被批准。直至 2015 年 5 月 HTTP/2 发布(详见 RFC7540)取代 HTTP/1.1 成为 HTTP 的实现标准。

小贴士:说到 HTTP/2 协议就不得不提谷歌的 SPDY 协议,在 2009 年谷歌公开了自行研发的 SPDY 协议(含义及发音皆为 SPeeDY)主要解决 HTTP/1.1 效率不高的问题。世界上最大的视频网站 YouTube 最先进行了 SPDY 协议的尝鲜,这个协议在 Chrome 浏览器上证明可行以后,就被当作 HTTP/2 的基础,主要特性都在 HTTP/2 之中得到继承。SPDY 并不是新的一种协议,而是在 HTTP 之前做了一层会话层。为了达到减少页面加载时间的目标,SPDY 引入了一个新的二进制分帧数据层,以实现优先次序、最小化及消除不必要的网络延迟,目的是更有效地利用底层 TCP 连接。

在 2015 年,互联网标准委员会不打算再发布 HTTP/2 子版本了,于是 HTTP/2 不写作 HTTP/2.0 ,下一个新版本将是 HTTP/3。

HTTP/2 版本中添加了很多特性,解决了 HTTP/1.1 中的缺点,以下选择部分重点特性进行说明。

H1/H2/H3协议对比

HTTP/3

说到 HTTP/3 就不得不再次提到谷歌,没错还是它!

QUIC (Quick UDP Internet Connections)是由 Google 从 2013 年开始研究的基于 UDP 的可靠传输协议,它最早的原型是 SPDY + QUIC-Crypto + Reliable UDP,后来经历了 SPDY 转型为 2015 年 5 月 IETF 正式发布的 HTTP/2.0,以及 2016 年 TLS/1.3 的正式发布。2016 年成立,IETF 的 QUIC 标准化工作组启动,考虑到 HTTP/2.0 和 TLS/1.3 的发布,它的核心协议族逐步进化为现在的 HTTP/3.0 + TLS/1.3 + QUIC-Transport 的组合。

在说 HTTP/3 之前先说一说 HTTP/2 的不足,每次版本更新都是为了解决前一代存在的问题,或者扩充其特性,由于 HTTP/2 及之前的协议都是基于 OSI 模型中第四层传输层协议 TCP 协议实现的。因此 TCP 协议存在的问题在 HTTP/2 中也都存在。

HTTP/2 的缺点主要有如下两点:

三次握手

小贴士:为什么是三次握手?因为三次握手是建立可靠连接(双向确认ACT)所需的最少次数。

很显然,这些问题主要都是底层支撑的 TCP 协议造成的。HTTP/2 都是使用 TCP 协议来传输的,而如果使用 HTTPS (HTTP over TLS) 的话,还需要使用 TLS 协议进行安全传输,而使用 TLS 也需要一个握手过程,这样就需要有两个握手延迟过程:

小贴士:RTT(Round-Trip Time,往返时延),是指数据从网络一端传到另一端所需的时间。

总之,在真正传输数据之前,就已经消耗了 3~4 个 RTT 周期,以在中国大陆访问美国的本土网站为例,中美直连的链路一般需要 100ms 时间(根据所处大陆地域不同存在些许差别,在北上广等国际出口城市)。因此在传输网络数据前,仅仅是建立 HTTPS 连接的 RTT 时间已经消耗了近 500ms 的时间。

上文在介绍 HTTP/2 时就提到了,HTTP/2 的一大改进就是多路复用,让多个请求存在于同一个 TCP “管道”中,如果网络连接差,比如存在大量丢包时,此时 HTTP/2 的性能还不如 HTTP/1 ,因为 TCP 协议的可靠特点,当出现丢包时,会触发重传机制,丢失的包会重新传输一次或者多次,直到接收方确认为止,当 HTTP/2 出现丢包时,整个 TCP 连接都要开始等待重传,就会阻塞此 TCP 管道中的所有请求。而对于 HTTP/1.1 来说,可以开启多个 TCP 连接,出现这种情况反到只会影响其中一个连接,剩余的 TCP 连接还可以正常传输数据。

实际上谷歌在开发 SPDY 协议时就意识到它存在的不足,因此同时开发了一个基于另一个传输层协议 UDP 的的 QUIC 协议,此协议就是 HTTP/3 的基础模型。在 2018 年 11 月互联网正式批准了 HTTP-over-QUIC 成为下一代 HTTP/3 协议,其在 HTTP/2 的基础上实现了很多飞跃,较完美的解决了队头阻塞问题。

由于 HTTP/3 基于用户数据报协议(UDP,User Datagram Protocol),此协议相比较于 TCP 可靠连接,最大的特点就是无状态、不可靠。因此可以实现 O 个 RTT 周期完成连接并开始传输数据,也就解决了队头阻塞问题。

HTTP/3 版本中添加了很多特性,解决了 HTTP/2 中的缺点,以下选择部分重点特性进行说明。

目前主流浏览器已经支持了 HTTP/3 ,但是需要服务端的支持,这将是一个较为漫长的过程。


常用 HTTP 服务

常用网页服务

市场占有率

DeveloperJune 2018PercentJuly 2018PercentChange
Apache76,721,59735.23%76,312,57734.60%-0.63
Microsoft56,030,49125.73%57,395,89426.02%0.29
NGINX50,860,71823.35%50,246,24422.78%-0.57
Google1,909,6580.88%1,948,8580.88%0.01

表格数据来源


附录

状态码表

参考链接

本文撰写于一年前,如出现图片失效或有任何问题,请在下方留言。博主看到后将及时修正,谢谢!
禁用 / 当前已拒绝评论,仅可查看「历史评论」。
  1. avatarImg zongsir

    写的不错,get 了

    Chrome 78.0 macOS Mojave
    IP 属地 未知