我正在尝试更新我们的在线商店以使用具有服务器推送功能的 HTTP/2,但我找不到像 Nginx(用于代理和其他一些东西)这样的具有上游 HTTP/2 的网络服务器的解决方案。我们目前正在使用 Node.js 和 node HTTP 模块,但想切换到 node spdy 模块。spdy 模块支持 HTTP/2 和服务器推送。我曾尝试将 H2O 作为 Nginx 的替代品,但它也不支持上游的 HTTP/2。
我现在有点迷路,需要帮助。
Nginx刚刚添加了对 HTTP/2 Push 的支持,所以除非你正在修改最新的主线版本,否则你将无法做到这一点。也因为它太新了,它仍然存在一些问题。Nginx 不支持通过后端连接的 http2(并且已经声明他们不会支持这个)。因此,您不能像您建议的那样直接从下游系统一直向上推送。
无论如何,这是否是最好的推动方式存在一些问题。即使客户端不支持推送,下游系统也可以推送到上游代理服务器——这是一种浪费的推送。
所以更好的方法是从代理推送,让下游系统告诉上游系统(通过链接头)进行推送。这在降低复杂性方面有几个优点,允许下游系统推送它可能无法控制的资产(例如,样式表、JavaScript、图像等静态资产),已推送资产(缓存摘要)的中央存储,也不是要求始终支持 HTTP/2(链接标头可以通过 HTTP/1.1 像 HTTP/2 一样容易地发送)。
通过链接头从上游代理推送的主要缺点是,当从响应中读取链接头时,您必须等待请求的资源准备好。如果请求资源需要一些时间来生成,那么在处理它的同时开始推送其他资源可能更有益。这可以通过新的103 Early Hints HTTP 状态代码解决,您可以在稍后发送主要的 200 状态代码之前提前回复。该早期消息可以具有上游代理可以读取并用于推送资源的链接标头。我不确定 Nginx 实现是否会支持这一点。
顺便说一句,Apache 已经支持 Push 有一段时间了,并且有一个更成熟的实现。它通过直接的 Apache 配置或链接头来支持它(包括通过默认配置为不发送的 103 响应,以防出现兼容性问题)。它甚至支持通过 HTTP/2 代理到后端,但由于上述原因不支持直接推送后端连接。其他一些不太知名的服务器(例如H2O)也比 Nginx 更好地支持 HTTP/2。
最后,如果使用 CDN,那么它们可能支持 HTTP/2 推送(通常通过链接头),而您无需升级任何后端基础设施。事实上,Cloudflare 是一个基于 Nginx 的 CDN,它使用HTTP/2 Push 已经有一段时间了,我实际上是两个 Cloudflare 工程师将他们的实现反向移植到了基本的 Nginx 代码。
在 NGINX 1.13.9(今天刚刚推送到主线)之后,您可以通过使用ngx_http_v2_module
.
如果您对最近添加的内容感兴趣,这是添加大部分功能的提交:hg.nginx.org: HTTP/2: server push。
它的使用相对简单:将http2_push_preload
指令添加到代理节点的服务器,然后从节点使用Link
标头(如 W3 规范中所述 - https://www.w3.org/TR/preload/#server- push-http-2),然后 NGINX 将完成发送指示服务器推送的 h2 帧的工作。
例如,假设您有一个/
提供常规服务index.html
但也推image.svg
送到客户端的端点。
在 NGINX 中,您可以配置上游服务器,然后在服务器配置中启用http2_push_preload
服务器配置:
# Add an upstream server to proxy requests to.
upstream sample-http1 {
server localhost:8080;
}
server {
# Listen on port 8443 with http2 support on.
listen 8443 http2;
# Enable TLS such that we can have proper HTTP2
# support using browsers.
ssl on;
ssl_certificate certs/cert_example.com.pem;
ssl_certificate_key certs/key_example.com.pem;
# Enable support for using `Link` headers to indicate
# origin server push.
http2_push_preload on;
# Act as a reverse proxy for requests going to /proxy/*.
#
# Because we don't want to rewrite our endpoints in the
# Node app, rewrite the path such that `/proxy/lol` ends up
# as `/lol`.
location / {
proxy_pass http://sample-http1;
}
}
然后在 NodeJS 应用程序中,您将像往常一样提供服务,但在响应中/
添加一个额外的标头:Link
response.setHeader('Link', '</image.svg>; rel=preload; as=image');
ps.:是的,你会保留那些尖括号;我并不是说你应该更换它们。
顺便说一句,我刚刚给出的示例(带有一些调试提示)已完整地写在这里:https ://ops.tips/blog/nginx-http2-server-push/ 。
您可以从源代码编译/重新编译 nginx 并包含--with-http_v2_module
配置参数以启用 HTTP2 推送功能。