最近H5被插广告愈演愈烈,于是打算给H5增加HTTPS支持。既然都支持了HTTPS,那么HTTP/2也就顺便来支持一下好了,反正SSL证书已经不是问题了。
我们是全容器环境,包括前端机在内,全部跑在容器里,更新前端nginx容器配置即可。Nginx从1.9.5版本开始支持HTTP/2的,查了一下满足条件。从HTTPS到HTTP/2,只需要:
server { listen 443 ssl http2; }
即可。
但是会有一些问题。协议协商包括NPN和ALPN两种,NPN是SPDY时代的产物,HTTP/2定稿时已经被ALPN取代。我们的目标是支持HTTP/2,因此务必支持ALPN。
关于NPN和ALPN的区别,可以参考这篇文章:《为什么我们应该尽快支持 ALPN?》我引用其中的梗概描述:
NPN(Next Protocol Negotiation,下一代协议协商),是一个 TLS 扩展,由 Google 在开发 SPDY 协议时提出。随着 SPDY 被 HTTP/2 取代,NPN 也被修订为 ALPN(Application Layer Protocol Negotiation,应用层协议协商)。二者目标一致,但实现细节不一样,相互不兼容。以下是它们主要差别:
- NPN 是服务端发送所支持的 HTTP 协议列表,由客户端选择;而 ALPN 是客户端发送所支持的 HTTP 协议列表,由服务端选择;
- NPN 的协商结果是在 Change Cipher Spec 之后加密发送给服务端;而 ALPN 的协商结果是通过 Server Hello 明文发给客户端;
需要注意的是,OpenSSL 1.0.2 才开始支持 ALPN。因此需要升级OpenSSL才可以。
由于OpenSSL是系统广泛依赖的基础库,不可贸然升级,对于我们来说,只需要选择合适的Nginx容器镜像即可。
目前官方的Nginx镜像维护了这些版本:
latest, 1, 1.11, 1.11.1 (mainline/jessie/Dockerfile)
stable, 1.10, 1.10.1 (stable/jessie/Dockerfile)
mainline-alpine, alpine, 1-alpine, 1.11-alpine, 1.11.1-alpine (mainline/alpine/Dockerfile)
stable-alpine, 1.10-alpine, 1.10.1-alpine (stable/alpine/Dockerfile)
Alpine的软件包一向更新迅速,nginx镜像基于alpine的3.3版本构建,使用的OpenSSL是1.0.2h-r1,满足要求。于是升级容器镜像为nginx:alpine。
重启之后Chrome和Safari可以正常通过HTTP/2访问了,但是Firefox却不行,打不开网页,也并没有报错。于是使用SSL诊断工具,看一下情况:
在Firefox 46 / Win 7一项中,显示:
Server negotiated HTTP/2 with blacklisted suite RSA 2048 (SHA256)
在Firefox的官方社区,找到了这个问题:
然而并没有人回复,原作者选择降级回http/1.1回避了这个问题。于是打算一探究竟,爆栈网的回答多半指向使用了不安全的加密选项,于是开始尝试调整加密选项。
这篇文章给了一个很好的建议:
把Nginx的ciphers设为:
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_stapling on; ssl_ciphers "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"; ssl_prefer_server_ciphers on;
重载配置之后解决,现在绝大多数支持HTTP/2的浏览器,都可以通过HTTP/2来访问了。
那么切换到HTTP/2之后性能提升了多少呢?我暂时还没有做数据的对比测试,主观感受H5在浏览器中打开的速度明显加快了,尤其是第二页打开时间,几乎是秒开。有时间的话,我再做客观数据的对比分析吧。
升级过程中的一些小Tips:
- Chrome可以通过chrome://net-internals/#http2来观察当前HTTP2的连接情况,控制台默认不显示网络通讯的协议,可以在列头上右键选择Protocol来显示。HTTP/2协议显示为h2。
- 如果静态资源是在CDN上的,那么CDN也支持http2才是最好的。我们目前使用阿里云CDN,只要配置了SSL证书,就默认支持HTTP/2。
一些参考文章:
- https://yq.aliyun.com/articles/7171
- https://www.textarea.com/zhicheng/fenxiang-yige-https-a-di-nginx-peizhi-320/
- https://imququ.com/post/enable-alpn-asap.html
- http://security.stackexchange.com/questions/126775/understanding-blacklisted-ciphers-for-http2
- https://support.mozilla.org/zh-CN/questions/1127467
@mark