HTTP/2是一个二进制协议,其基于“帧”的结构设计,改进了不少HTTP/1.1痛点问题。下面列举一些最常被津津乐道的改进之处:css
以上列举的每一项都值得作深刻细致的研究,这里就只针对“多路复用”功能的实现进行深刻的学习。html
网络上有一张图能清晰的解释这个问题:
HTTP/1.1协议的请求-响应模型你们都是熟悉的,咱们用“HTTP消息”来表示一个请求-响应的过程,那么HTTP/1.1中的消息是“管道串形化”的:只有等一个消息完成以后,才能进行下一条消息;而HTTP/2中多个消息交织在了一块儿,这无疑提升了“通讯”的效率。这就是多路复用:在一个HTTP的链接上,多路“HTTP消息”同时工做。前端
简单回答就是:HTTP/2是基于二进制“帧”的协议,HTTP/1.1是基于“文本分割”解析的协议。
看一个HTTP/1.1简单的GET请求例子:web
GET / HTTP/1.1 Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Accept-Encoding:gzip, deflate, br Accept-Language:zh-CN,zh;q=0.9,en;q=0.8 Cache-Control:max-age=0 Connection:keep-alive Cookie:imooc_uuid=b2076a1d-6a14-4cd5-91b0-17a9a2461cf4; imooc_isnew_ct=1517447702; imooc_isnew=2; zg_did=%7B%22did%22%3A%20%221662d799f3f17d-0afe8166871b85-454c092b-100200-1662d799f4015b%22%7D; loginstate=1; apsid=Y4ZmEwNGY3OTUwMTdjZTk0ZTc4YzBmYThmMDBmZDYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANDEwNzI4OQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5NTMzNjIzNjVAcXEuY29tAAAAAAAAAAAAAAAAAAAAADBmNmM5MzczZTVjMTk3Y2VhMDE2ZjUxNmQ0NDUwY2IxIDPdWyAz3Vs%3DYj; Hm_lvt_fb538fdd5bd62072b6a984ddbc658a16=1541222935,1541224845; Hm_lvt_f0cfcccd7b1393990c78efdeebff3968=1540010199,1541222930,1541234759; zg_f375fe2f71e542a4b890d9a620f9fb32=%7B%22sid%22%3A%201541297212384%2C%22updated%22%3A%201541297753524%2C%22info%22%3A%201541222929083%2C%22superProperty%22%3A%20%22%7B%5C%22%E5%BA%94%E7%94%A8%E5%90%8D%E7%A7%B0%5C%22%3A%20%5C%22%E6%85%95%E8%AF%BE%E7%BD%91%E6%95%B0%E6%8D%AE%E7%BB%9F%E8%AE%A1%5C%22%2C%5C%22%E5%B9%B3%E5%8F%B0%5C%22%3A%20%5C%22web%5C%22%7D%22%2C%22platform%22%3A%20%22%7B%7D%22%2C%22utm%22%3A%20%22%7B%7D%22%2C%22referrerDomain%22%3A%20%22%22%2C%22cuid%22%3A%20%22Jph3DQ809OQ%2C%22%7D; PHPSESSID=h5jn68k1fcaadn61bpoqa9hch2; cvde=5be7a057c314b-1; IMCDNS=1 Host:www.imooc.com Referer:https://www.imooc.com/ Upgrade-Insecure-Requests:1 User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36
以上就是HTTP/1.1发送请求消息的文本格式:以换行符分割每一条key:value的内容,解析这种数据用不着什么高科技,相反的,解析这种数据每每速度慢且容易出错。“服务端”须要不断的读入字节,直到遇到分隔符(这里指换行符,代码中可能使用/n或者/r/n表示),这种解析方式是可行的,而且HTTP/1.1已经被普遍使用了二十多年,这事已经作过无数次了,问题一直都是存在的:算法
前边提到:HTTP/2设计是基于“二进制帧”进行设计的,这种设计无疑是一种“高超的艺术”,由于它实现了一个目的:一切可预知,一切可控。
帧是一个数据单元,实现了对消息的封装。下面是HTTP/2的帧结构:
帧的字节中保存了不一样的信息,前9个字节对于每一个帧都是一致的,“服务器”解析HTTP/2的数据帧时只须要解析这些字节,就能准确的知道整个帧指望多少字节数来进行处理信息。咱们先来了解一下帧中每一个字段保存的信息:浏览器
名称 | 长度 | 描述 |
---|---|---|
Length | 3 字节 | 表示帧负载的长度,默认最大帧大小2^14 |
Type | 1 字节 | 当前帧的类型,下面会作介绍 |
Flags | 1 字节 | 具体帧的标识 |
R | 1 字节 | 保留位,不须要设置,不然可能带来严重后果 |
Stream Identifier | 31 位 | 每一个流的惟一ID |
Frame Payload | 不固定 | 真实帧的长度,真实长度在Length中设置 |
若是使用HTTP/1.1的话,你须要发送完上一个请求,才能发送下一个;因为HTTP/2是分帧的,请求和响应能够交错甚至能够复用。
为了可以发送不一样的“数据信息”,经过帧数据传递不一样的内容,HTTP/2中定义了10种不一样类型的帧,在上面表格的Type字段中可对“帧”类型进行设置。下表是HTTP/2的帧类型:缓存
名称 | ID | 描述 |
---|---|---|
DATA | 0x0 | 传输流的核心内容 |
HEADERS | 0x1 | 包含HTTP首部,和可选的优先级参数 |
PRIORITY | 0x2 | 指示或者更改流的优先级和依赖 |
RST_STREAM | 0x3 | 容许一端中止流(一般是因为错误致使的) |
SETTINGS | 0x4 | 协商链接级参数 |
PUSH_PROMISE | 0x5 | 提示客户端,服务端要推送些东西 |
PING | 0x6 | 测试链接可用性和往返时延(RTT) |
GOAWAY | 0x7 | 告诉另一端,当前端已结束 |
WINDOW_UPDATE | 0x8 | 协商一端要接收多少字节(用于流量控制) |
CONTINUATION | 0x9 | 用以拓展HEADER数据块 |
有了以上对HTTP/2帧的了解,咱们就能够解释多路复用是怎样实现的了,不过在这以前咱们先来了解“流”的概念:HTTP/2链接上独立的、双向的帧序列交换。流ID(帧首部的6-9字节)用来标识帧所属的流
下面两张图分别表示了HTTP/2协议上POST请求数据流“复用”的过程,很容易看的明白:服务器
因为HTTP/2消息中“帧”的设计,客户端和服务端在通讯的过程当中可以彼此了解更多的信息。下面再简单说一下其余几点比较重要的特性,算是一个学习引导方向吧。网络
HTTP/2的新特性之一是基于流的流量控制。不一样于HTTP/1.1,只要客户端能够处理,服务端就会尽量快的发送数据,HTTP/2提供了客户端调整传输速度的能力(服务端也能够)。WINDOW_UPDATE帧用来完成这件事情,每一个帧告诉对方,发送方想要接收多少字节,它将发送一个WINDOW_UPDATE帧以指示其更新后的处理字节能力。app
流的一个重要特性是能够设置优先级和资源数据的依赖关系。HTTP/2经过流的依赖能够实现这些功能。经过HEADERS帧和PRIORITY帧,客户端能够明确的告诉服务端它最须要什么,这是经过声明依赖关系和权重实现的。
《孙子兵法》中有一句名言:“兵马未到,粮草先行”。服务端推送功能就能够实现这样一个功能。当页面尚未开始请求具体的资源时,服务端就已经把一些资源(像css和js)已经推送到客户端了。当浏览器要渲染页面时,资源已经在缓存中了,听起来是一件很酷的事情,实际上也正是这样。服务端推送是经过PUSH_PROMISE帧实现的,固然其实现的细节是很是复杂的,感兴趣的同窗能够研究一下。HTTP/2的“多路复用”问题已经说明白了,还补充了一些新特性的介绍。固然想要深刻了解HTTP/2的一些原理,有太多太多的内容须要阅读,实践。好比“首部压缩”算法HPACK是HTTP/2的关键元素之一,是HTTP/2制定开发组长时间的研究成果,其思想内容也是特别值得学习借鉴的。本节所设计到的东西只是HTTP/2协议中的冰山一角,RFC7540能够帮助你充分了解该协议的方方面面。