HTTP/1、HTTP/1.1 和 HTTP/2 的区别
2023年2月10日
从 1989 年起,HTTP 经历了数代的演化,从 1 到 1.1 再到 2 以及目前的 3,这些不同版本有些什么不同呢?不管是前端或后端的面试,都是经常会考的。这篇我们会先针对 1 到 1.1 再到 2 之间的异同处做摘要。
出现时间
超文本传输协定 HTTP (HyperText Transfer Protocol) 是在网际网路中用来通信数据的基础。 HTTP 一开始的发展是从 1989 年所发起制定,其中经过几个时期的演进,HTTP/1.1 是随着在 1999 年 6 月公布的[RFC 2616](https://tools.ietf.org/html /rfc2616) 所发表。 HTTP/2 (最初命名为 HTTP 2.0) 则是在 2015 年 5 月以RFC 7540 正式发表,并取代 HTTP/1.1 成为 HTTP 的实作标准。截至 2021 年 10 月,全球有 46.5%的网站支援了 HTTP/2 (wiki)。
HTTP/1 和 HTTP/1.1 差异
往下读之前,要先理解之所以会有 HTTP/1.1 是因为 HTTP/1 有一些不那么理想的地方。因此建议不要死背差异,而是从「 HTTP/1.1 解决了什么问题」出发来理解。
持久连接 (keep-alive)
HTTP/1 在发送每个请求之前都需要建立一个新的连接,而每次连接都是有成本的,这种每次重连的方式会造成很多频宽的浪费,以及时间的延迟。而 HTTP/1.1 默认使用持久连接,让 HTTP/1.1 可以使用同一个 TCP 连接来重复多个 HTTP 请求,这么一来就可以避免每次重新建立连接造成的频宽浪费、时间延迟。
状态码 100 (Continue)
在某些情况下,服务器端会拒绝客户端发送的请求,因为发请求时可能会夹带正文 (request body),所以每次请求被拒绝都会造成频宽上的额外浪费。在 HTTP/1 没有机制避免这种类型的浪费,而 HTTP/1.1 的 100 (Continue)
状态码则可以协助我们避免这种浪费。
具体来说,HTTP/1.1 让使用者端先送出一个只含有标头、不带内文的请求到服务器,服务器确认没有问题之后,会回应状态码100 (Continue)
;收到 100 (Continue)
后,客户端才会正式发一个带有正文的请求;如果没有收到,则代表服务器端不接受该请求,这让客户端知道服务器端不接受,这能让客户端可以避免发带有正文的请求,进而减少传输上的频宽浪费。 (详细请见 RFC 的这个段落)。
快取缓存
HTTP/1 主要使用标头中的If-Modified-Since
、Expires
来做为缓存的判断标准,这两者都是以时间作为依据;HTTP/1.1 则引入更多的缓存策略,例如:Etag
、If-Unmodified-Since
、If-Match
、If-None-Match
,透过这些可以更优化缓存的实现。
延伸阅读:请解释 HTTP caching 机制
Host 字段
HTTP/1.1 增加了 Host 字段,用来指定服务器的域名。在 HTTP/1 中,会认为每台服务器都绑定唯一的 IP 地址,因此请求当中的 URL 并没有传递主机名(hostname)。但随着之后虚拟主机技术的演进,现在在一台服务器上可以存在多个虚拟主机,并且他们会共享同一个 IP 地址。所以有了 host 字段之后,就可以将请求发往同一台服务器上的不同网站。
更多请求方法
HTTP/1.1 相对于 HTTP/1 新增了许多请求方法,现今我们常用的PUT
、PATCH
、DELETE
、CONNECT
、TRACE
和OPTIONS
等都是在 HTTP/1.1 时新增的。
HTTP/2 和 HTTP/1.1 比较
多路复用(Request multiplexing) 来解决头部阻塞 (head-of-line blocking)
HTTP/1.1 使用了 pipelining 的机制,这可以让客户端在同一个 TCP 连接内并行发出多个 HTTP 请求,客户端也不需要等待上一次请求结果返回,就可以发出下一次请求,但服务器端必须依照接收到的客户端请求的先后顺序一次返回,以保证客户端能够区分出每次请求的回应内容,但这项机制在实作上较难实现,因此各家浏览器,都将此功能预设为关闭(可以参考此篇 Stack Overflow)。
此外 pipeline 也造成头部阻塞 (head-of-line blocking, HOL) 问题,如果有任一个请求要操作很久或传输包流失,那就会阻塞整个 pipeline 的工作。
HTTP/2 引进了多路复用的机制,让同一个 TCP 连接中,同时发送和接受多个请求,并且不用等到前一个请求收到回应,透过这个机制,解决了过往在 HTTP 层级的的头部阻塞问题(备注:但 TCP 层级仍有头部阻塞问题,这会在 HTTP/3 被解决)。
延伸阅读:TCP 与 UDP 是什么?差异为何?
优先请求顺序
HTTP/2 版本中,每个请求或回应的所有数据包,称之为一个数据流,并且,每个数据流拥有一个唯一编号 ID (stream ID
)。每个数据包在发送的时候就会戴上对应的数据流编号 ID,客户端还能指定数据流的优先级,优先级越高服务器也会越快做出回应。
标头 (Header) 讯息压缩
在 HTTP/2 之前因为安全性问题,多数不会对标头的讯息进行压缩,主要是过去的采用的演算法可能遭受 CRIME 攻击。在 HTTP/2 中,使用 HPACK 算法来避免攻击,进而能压缩标头。因为压缩标头,让传输时能大幅减少传输的讯息量,进而减少频宽负担,也增快传输速度。具体上 HPACK 使用一份索引表来定义常用的 http header,并把 http header 存放在表里,请求的时候只需要发送在表里的索引位置即可,不须用传完整的标头。
服务器主动推送(Server push)
HTTP/2 允许服务器端主动向客户端推送数据,这能协助减少客户端的请求次数。举例来说,浏览器在过去要请求index.html
与style.css
来渲染完整的画面;透过 Server Push,可以在浏览器请求index.html
时,也由服务器主动发送 style.css
,这样只需要一轮 HTTP 的请求,就可以拿到所需的所有资源。