HTTP/2 新特性浅析

HTTP发展简史

HTTP/0.9

  • 1991年发布
  • 只支持GET命令
  • 请求及返回值都是ASCII码
  • 请求以换行符(CRLF)结束
  • 返回值只支持HTML格式
  • 服务器返回值之后立刻关闭连接
GET /index.html

HTTP/1.0

  • 1996年发布
  • 除了GET命令,还增加了POST和HEAD命令
  • 服务器支持返回任意格式
  • 请求和返回值除了包含数据部分,还增加头部信息(HTTP header)
  • 返回值增加状态码(status code)
GET / 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/plain
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

<html>
  <body>Hello World</body>
</html>

HTTP/1.1

  • 1997年发布
  • 支持持久连接(Connection: keep-alive),即TCP连接默认不关闭,可以被多个请求复用
  • 支持管道机制(pipelining),即一个TCP连接内可以同时发起多个请求
  • 支持分块传输编码(chunked transfer encoding)
  • 支持断点续传(Accept-Ranges)
  • 支持更多命令,如PUT, PATCH, OPTIONS, DELETE
  • 尽管支持复用TCP连接,但仍然会产生队头阻塞(Head-of-line blocking)问题

HTTP/2

  • 2015年发布
  • 2009年Google自行研发的SPDY在Chrome上验证成功后,被当作是HTTP/2的基础
  • 完全采用二进制协议
  • 支持多路复用(multiplexing)
  • 支持头部压缩(header compression)
  • 支持服务器推送(server push)

二进制协议

HTTP/2之前的协议都是基于ASCII码,好处是可读性好,容易上手。其缺点是可选的空格以及多变的终止符给识别帧造成了一些困难。采用二进制协议可以使得帧的识别更简单,并且传输信息更高效。其缺点是不便于调试,这就需要我们使用相应的工具来理解二进制的内容。

HTTP/2完全采用二进制协议,头信息和数据体都是二进制的,统称为(frame)。下图展示了同一个请求在HTTP/1.1和HTTP/2的对应关系,可见请求在HTTP/2中分为了两部分:头部帧和数据帧。

一个帧的基本格式如下:

所有帧都由一个9字节的header和可变长的payload组成,各字段定义如下:

  • Length: 表示payload的长度,payload的长度默认不能超过214 (16,384) ,除非修改SETTINGS_MAX_FRAME_SIZE为更大的值
  • Type: 表示帧的类型,比如0x0表示数据帧,0x1表示头部帧,类型不在规范里定义的帧将会被丢弃
  • Flags: 对于不同类型的帧,这个字段有不同的含义,比如在数据帧里,0x1表示这个frame是流的最后一帧(END_STREAM)
  • R: 保留位,这一位必须置为0并且需要被忽略
  • Stream Identifier: 流ID,客户端发起的流ID必须是奇数的,服务端发起的流ID必须是偶数的

多路复用

为了说明什么是多路复用,我们先需要明确下面几个概念:

  • (stream): 已建立的连接内的双向字节流,可以承载一条或多条消息
  • 消息(message): 与逻辑请求或响应消息对应的完整的一系列帧
  • (frame): HTTP/2 通信的最小单位,每个帧都包含帧头,至少也会标识出当前帧所属的数据流

这些概念的关系总结如下:

  • 所有通信都在一个 TCP 连接上完成,此连接可以承载任意数量的双向数据流
  • 每个数据流都有一个唯一的标识符和可选的优先级信息,用于承载双向消息
  • 每条消息都是一条逻辑 HTTP 消息(例如请求或响应),包含一个或多个帧
  • 帧是最小的通信单位,承载着特定类型的数据,例如 HTTP Header、消息负载等等。 来自不同数据流的帧可以交错发送,然后再根据每个帧头的数据流标识符重新组装

在HTTP/1.1中,如果客户端为了提高性能想要在一个TCP连接内同时发起多个请求,每个请求必须按顺序被服务器依次响应,如果某一个请求特别耗时,那么后面的请求将会被一直阻塞。

而在HTTP/2中,如果在一个TCP连接内同时发起多个请求,每个消息可以被拆成互不依赖的帧并且各帧之间交错发送,然后在另一端重新把帧组装起来。这个特性就叫做多路复用。

上图展示了同一个连接内并行的多个数据流。客户端正在向服务器传输一个数据帧(数据流5),与此同时,服务器正向客户端交错发送数据流1和数据流3的一系列帧。因此,一个连接上同时有三个并行数据流。

头部压缩

每个HTTP请求时都会承载一组表头。在HTTP/1.x中表头是以纯文本形式传输,通常需要500~800字节的开销,如果有cookie的话甚至会达到上千字节。为了减少这种开销并且提升性能,HTTP/2使用了HPACK算法进行压缩,具体来说包含了如下两种简单并强大的技术:

  • 头部字段使用静态Huffman编码,如果编码后使得字符反而变长了,那么不采用Huffman编码
  • 客户端和服务器同时维护并更新一个索引表,如果传输的值在索引表里,那么使用索引值作为传输的值。索引表分为静态表和动态表两部分,静态表在规范里定义,包含了一些常用的字段,动态表初始为空,在连接过程中动态更新

如上图所示,最左边是原始的请求头,第一行的:method GET通过查找静态索引表得到索引值为2,所以HPACK算法将其编码为2。最后第二行的user-agent Mozilla/5.0 ...不在静态索引表里,但在动态索引表里查到索引值为62,所以HPACK算法将其编码为62。最后一行的两个字段均未在索引表里查到,所以分别对其进行Huffman编码。

服务器推送

HTTP/2新增的另一个强大的功能是允许服务器除了可以响应客户端请求,还可以向客户端推送额外的资源。

通常当我们请求一个网页时,客户端解析HTML源码,发现有js或css等其他静态资源,然后再发起请求下载静态资源。而实际上,当客户端请求网页后,服务器完全可以预判客户端接下来要请求相关的静态资源,那为什么不让服务器提前推送这些资源,从而减少额外的延迟时间呢?HTTP/2为此提出了服务器推送机制,服务器端可以通过发起PUSH_PROMISE帧告知客户端,客户端收到服务器想要推送资源的意图后,可以决定是否接收推送。

事实上,如果你在网页中内联CSS或Javascript,那么你已经体验过服务器推送了。使用HTTP/2,我们不仅可以获得相同效果,还可以获得更多的性能优势:

  • 客户端可以缓存推送资源
  • 推送资源可以被不同页面重用
  • 推送资源可以与其他资源复用
  • 推送资源可以由服务器设定优先级
  • 推送资源可以被客户端拒绝(非强制推送)

服务器推送功能虽然很强大,但在实际使用中还需要考虑一些问题。第一个问题是如果客户端已经有缓存了,那么推送资源就是一种浪费。一种解决方法是只在用户第一次访问的时候推送资源。第二个问题是目前我们一般把静态资源放在CDN上,目前大部分CDN还不支持服务器推送,那么CDN和服务器推送到底哪个效果更好,这个可能还需要一些测试数据来做评判。

参考资料

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容