HTTP/2协议介绍
HTTP/2源于SPDY, 主要目标是解决HTTP 1.x的性能问题.
有别于HTTP/1.1在连接中的明文请求,HTTP/2与SPDY一样,将一个TCP连接分为若干个流(Stream),每个流中可以传输若干消息(Message),每个消息由若干最小的二进制帧(Frame)组成。这也是HTTP/1.1与HTTP/2最大的区别所在。
新特性
- 头数据压缩 Data compression of HTTP headers
- 服务器推送 HTTP/2 Server Push
- 管线化请求 Pipelining of requests
- HTTP 1.x队头阻塞问题的解决 Fixing the head-of-line blocking problem in HTTP 1.x
- 对数据传输采用多路复用,让多个请求合并在同一 TCP 连接内 Multiplexing multiple requests over a single TCP connection
此外, HTTP/2 采用了二进制而非明文来打包、传输客户端—服务器间的数据。
名词解析:
队头阻塞
队头阻塞(Head-of-line blocking或缩写为HOL blocking)在计算机网络的范畴中是一种性能受限的现象。它的原因是一列的第一个数据包(队头)受阻而导致整列数据包受阻。例如它有可能在缓存式输入的交换机中出现,有可能因为传输顺序错乱而出现,亦有可能在HTTP流水线中有多个请求的情况下出现。
管道化请求
管道化请求(英语:HTTP pipelining)是将多个HTTP请求(request)整批提交的技术,而在发送过程中不需先等待服务端的回应。
请求结果管线化使得 HTML 网页加载时间动态提升,特别是在具体有高延迟的连接环境下,如卫星上网。在宽带连接中,加速不是那么显著的,因为需要服务器端应用 HTTP/1.1 协议:服务器端必须按照客户端的请求顺序恢复请求,这样整个连接还是先进先出的,队头阻塞(HOL blocking)可能会发生,造成延迟。 HTTP/2.0 或者SPDY中的异步操作将会解决这个问题。因为它可能将多个 HTTP 请求填充在一个TCP数据包内,HTTP 管线化需要在网络上传输较少的 TCP 数据包,减少了网络负载。
管线化机制须通过永久连接(persistent connection)完成,并且只有 GET 和 HEAD 等要求可以进行管线化,非幂等的方法,例如POST将不会被管线化。连续的 GET 和 HEAD 请求总可以管线化的。一个连续的幂等请求,如 GET,HEAD,PUT,DELETE,是否可以被管线化取决于一连串请求是否依赖于其他的。此外,初次创建连接时也不应引导管线机制,因为对方(服务器)不一定支持 HTTP/1.1 版本的协议。
HTTP 管线化同时依赖于客户端和服务器的支持。遵守 HTTP/1.1 的服务器支持管线化。这并不是意味着服务器需要提供管线化的回复,而只是要求在收到管线化的请求时候不会失败。
多路复用
多路复用(Multiplexing,又称“多工”)是一个通信和计算机网络领域的专业术语,在没有歧义的情况下,“多路复用”也可被称为“复用”。多路复用通常表示在一个信道上传输多路信号或数据流的过程和技术。因为多路复用能够将多个低速信道整合到一个高速信道进行传输,从而有效地利用了高速信道。通过使用多路复用,通信运营商可以避免维护多条线路,从而有效地节约运营成本。
物理线路上的多路复用根据使用的技术可以分为时分复用(TDM)、频分复用(FDM)、空分复用(SDM)和码分复用(CDM).
HTTP/2里的多路复用指的是将一个TCP连接分为若干个流(Stream).
HPACK 算法
HPACK算法是新引入HTTP/2的一个算法,用于对HTTP头部做压缩。其原理在于:
客户端与服务端根据 RFC 7541 的附录A,维护一份共同的静态字典(Static Table),其中包含了常见头部名及常见头部名称与值的组合的代码;
客户端和服务端根据先入先出的原则,维护一份可动态添加内容的共同动态字典(Dynamic Table);
客户端和服务端根据 RFC 7541 的附录B,支持基于该静态哈夫曼码表的哈夫曼编码(Huffman Coding)。
服务器推送
网站为了使请求数减少,通常采用对页面上的图片、脚本进行极简化处理。但是,这一举措十分不方便,也不高效,依然需要诸多HTTP链接来加载页面和页面资源。
HTTP/2引入了服务器推送,即服务端向客户端发送比客户端请求更多的数据。这允许服务器直接提供浏览器渲染页面所需资源,而无须浏览器在收到、解析页面后再提起一轮请求,节约了加载时间。
服务器支持
web服务器
HTTP/2 自2015-5-4发表为RFC 7540以来,绝大多数主流web服务器已支持HTTP/2.
nginx 1.9.5 起, 支持 HTTP/2.配置也很简单
listen 443 ssl http2 default_server; Tomcat-8.5 起, 支持 HTTP/2.
需配置启用
<Connector ... > <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" /> </Connector>
更多参考 https://tomcat.apache.org/tom...
测试自己的服务器是否支持HTTP/2可以用这个地址: https://tools.keycdn.com/http... (似乎需要科学上网上行)
浏览器
多数主流浏览器的新版本在2015年底已增加对HTTP/2的支持.
在线测试: 点此访问来测试你的浏览器是否支持HTTP/2.
同样加载一个敲碎的地球图片, Chromium 64的测试结果不理想, HTTP/2 显著地比HTTP/1.1快,但延迟多一些, 有时还不够稳定. Firefox 59版似乎默认没有启用HTTP/2,需手工打开.
这个地址也可以进行类似的测试 https://http2.golang.org/
客户端组件
OkHttp 是一个 Android 下比较常用的 HTTP 客户端,支持 HTTP 和 HTTP/2 协议.
版本协商升级协议ALPN
OpenSSL 1.0.2 才开始支持 ALPN, 而nginx需要OpenSSL的ALPN才能实现HTTP/2相关的功能. Ubuntu 16.04已默认支持.
如浏览器支持HTTP/2, 则向服务器请求时会有Upgrade头:
GET / HTTP/1.1 Host: server.example.com Connection: Upgrade, HTTP2-Settings Upgrade: h2c HTTP2-Settings: <base64url encoding of HTTP/2 SETTINGS payload>
如服务不支持,不会有相应回应: (即响应里没有 "Upgrade" 头)
HTTP/1.1 200 OK Content-Length: 243 Content-Type: text/html ...
如服务器需要忽略Upgrade里的 "h2" 词素, 因为 "h2" 指 HTTP/2 over TLS, 会有不同的解析如下:
服务器支持 HTTP/2 接受升级,并在响应里回应一个101 状态码 (切换协议). 之后用空行结束 101 响应, 服务器可以开始发送 HTTP/2 数据帧. 这些帧必须包含一个响应用来回应协议初始化的请求.
如:
HTTP/1.1 101 Switching Protocols Connection: Upgrade Upgrade: h2c HTTP/2 connection ...
针对HTTP/2的批评意见
- 违反协议分层原则,在应用层上重复进行流控制(TCP层已有流控制)
- 不一致且过度复杂
- 时间短,没有经过长时间的完善,主要特性来源仅自SPDY
- 安全及加密的问题
总结
虽然HTTP/2标准出台已有三年,但不是所有浏览器默认支持. 目前来看用户自己能控制的客户端里, 做为客户端与服务端的协议更容易一些. 否则一定要做到优雅降级,在不支持HTTP/2的场景下能够通过HTTP/1.1完成同样的功能.
参考
开发与调试,curl及h2c编译支持HTTP/2: https://blog.cloudflare.com/t...
HTTP/2代码库: https://nghttp2.org/