从接入 HTTP/2 开始的杂谈
最近想给业务上 HTTP/2,查了许多文档都是介绍 HTTP/2 的优势,却很少有提及怎么接入 HTTP/2。
虽说最后发现可以在 NetLink 平台上对接入的域名开启 HTTP/2 ,但过程中仍然有一些疑问,因此也有了这篇文档。对于我这样的练习前端两年半的初学者来说,也是给自己查漏补缺,提升一下视野了。
HTTP/2 RFC
了解 HTTP/2 协议,最好先从它的 RFC 开始。
3. Starting HTTP/2 .................................................7
3.1. HTTP/2 Version Identification ..............................8
3.2. Starting HTTP/2 for "http" URIs ............................8
3.2.1. HTTP2-Settings Header Field .........................9
3.3. Starting HTTP/2 for "https" URIs ..........................10
3.4. Starting HTTP/2 with Prior Knowledge ......................10
3.5. HTTP/2 Connection Preface .................................11
冷知识,HTTP/2 的 RFC 文稿本身不支持 HTTP/2。 :)
HTTP/2 并不是像 http:// 或是 https:// 那样从 URI 就明显不同,从文稿中可以看出,在 HTTP/2 的设计中是可以使用 http 或是 https 实现,所以当你的网站接入了 HTTP/2 之后,为了防止接了个寂寞,通常需要一些额外的手段来确认是否接入成功。
而对于客户端使用 HTTP/2 也有两种方式:
一种是使用 ALPN(Application Layer Protocol Negotiation,应用层协议协商),这种方式通常是在 https下使用。另一种则是基于先验知识(Prior Knowledge),也就是客户端通过某种方式知道了远端服务器支持 HTTP/2,在连接开始的时候发送连接前言(Connection Preface),并立即使用 HTTP/2 建立连接。
不过目前主流的浏览器厂商只在 https 下实现了 HTTP/2,所以还在用 http 的网站还是先考虑升级到 https 吧。
对我来说,这里就产生了几个疑问:
-
假设我们自己搭一个私人的服务器,怎么接入 HTTP/2 ?
-
怎么才能看到网站接入 HTTP/2 是否成功?
-
从浏览器的角度,具体是怎么确认远端的服务器支持 HTTP/2 ?
对于知道答案的同学来说,易得。
但对于当时的我确实挺困惑的,让我们来一一探究这些问题。
如何接入 HTTP/2
HTTP/2 的多个优点(首部压缩、多路复用、二进制分帧等)更多是提升 Web 性能,所以接下来也主要介绍 Web 服务如何接入 HTTP/2。
Apache
Apache 的发展时期很长(最早版本发布于1995年),虽然市场份额渐渐被 Nginx 赶超,但其仍有 Nginx 取代不了的优点。
需要在 Apache 2.4.17 及以上版本才能开启 HTTP/2。
Apache 目前有三种稳定的 MPM (Multi-Processing Module,多进程处理模块) 模式,分别是 Prefork MPM 、Worker MPM、Event MPM。
Apache 推荐在 Event MPM 模式下开启 HTTP/2,我们先来看看这几个模式分别是什么:
Apache 使用配置部分较为简单,在 httpd.conf 文件中添加加载 mod_http2 模块,并设置使用即可(这里的配置都略去了 HTTPS 的配置)
# 全局生效
LoadModule http2_module modules/mod_http2.so
Protocols h2 http/1.1
# 部分生效
LoadModule http2_module modules/mod_http2.so
Protocols http/1.1
<VirtualHost ...>
ServerName test.example.org
Protocols h2 http/1.1
</VirtualHost>
注意: OpenSSL 版本
需要注意的是,使用 HTTP/2 也要求服务器上的 OpenSSL 版本为 1.0.2 及以上(目前最新的 LTS 版本是 1.1.1),而一些旧版本的操作系统选择在稳定的 OpenSSL 1.0.1 版本上做修复,对于这种情况下想要使用 HTTP/2 有几种方法:
-
升级操作系统 例如Ubuntu 14.04 版本中默认是使用的 1.0.1,可以选择升级到更新的 Ubuntu 版本 Ubuntu 16.04
-
全局安装 OpenSSL 的新版本,并升级使用的 Apache 或 Nginx 的版本,对于旧版本的操作系统,改动 OpenSSL 的版本可能会带来其他的风险。
Nginx
Nignx 分为开源版本的 Nginx 和有客户服务支持的 Nginx Plus,我们这里讨论的是开源版本的 Nginx。
需要在 Nginx 1.9.5 版本及以上才能开启 HTTP/2。
Nginx 是一个异步框架的 Web Server,不过它更多的用途是作为反向代理和负载均衡。最早人们大多使用 Nginx 作为 Apache 的补充,提供一些静态文件,但时过境迁,它已经发展为一个完整的 Web 服务器。在近些年间 Nginx 的使用率已经逐渐超越了 Apache。
相比 Apache,Nginx 的 IO 并发和静态文件方面的性能是比 Apache 好的,甚至是远远超越,原因必须追溯到底层设计的差异,这里也不作特别探讨了,感兴趣的同学可以去研究一下(serverguy.com/comparison/…
# 全局生效
server {
listen 443 ssl http2;
...
}
# 部分生效
server {
ssl_h2 on;
}
这里需要注意的是如果在任意一个 Nginx 的 server 配置中设置了 listen 443 ssl http2;这样的配置,会导致该 Nginx 里所有的 server 都开启了 HTTP/2 ,这可能会导致一些期望之外的结果。
按我的理解,后续 Nginx 开发组在 2017 年的一次 MR 中支持了 ssl_h2 on 这样的配置,这个配置只会在当前的 server中开启 HTTP/2。不过从搜索ssl_h2得到的记录看 Nginx 并没有在官方文档中提到这个配置,这也是个未解之谜了。
如何查看域名是否已经接入了 HTTP/2
既然无法从路由上区别,我们要怎么知道网站是否已经开启了 HTTP/2 呢?这里有两种方法。
- 使用 curl
# 通过 curl -I 可以打印 Response Header
curl -I https://www.google.com
可以看到响应 Header的第一行能看到请求使用的协议,Google 支持了 HTTP/2 ,而另一位受害者 4399 的网站只支持了 HTTTP/1.1。
- 通过 Chrome 浏览器的开发者工具也能看到网络请求的协议,不过需要稍微设置一下:
在 Network 里右键任意一个表头,在下拉菜单中选择 Protocol ,之后就能看到每个请求的协议了。
浏览器如何识别服务器支持 HTTP/2
HTTP/2 协议本身并没有要求它必须基于 https 部署,但目前的主流浏览器都只支持 https 下的 HTTP/2 。那么浏览器在访问 https 链接的时候,是怎么知道服务器支持 HTTP/2,并在接下来的请求中使用该协议呢?
我们先来回顾一下 https 通信的流程:
是否有想到什么呢,在这个阶段其实也可以完成 HTTP 版本的协商。这就是前面在 HTTP/2 的协议中提到的 ALPN。
客户端在建立 TLS/SSL 连接的 Client Hello 握手中,会通过 ALPN 拓展列出自己支持的各种应用层协议。然后服务端可以按需从中选择,并在 Server Hello 中指定具体要使用的协议。
让我们用 curl 来看看这一段是什么样的。
# 通过 curl -v 可以看到通信的整个过程
curl -v https://www.google.com
可以看到,客户端通过 ALPN 告知服务端支持的 HTTP/1.1 和 HTTP/2 两个协议,而服务端选择了 HTTP/2 作为之后使用的协议。这个流程是建立在客户端和服务端都支持 ALPN 的前提下。
支持 HTTP/2 的 Web Server 基本都支持 HTTP/1.1。这样,即使浏览器不支持 HTTP/2,双方也可以协商出可用的 HTTP 版本,没有兼容性问题。
转载自:https://juejin.cn/post/7176476070341230648