编程

在 Apache 中实现 HTTP2

1291 2023-04-15 20:30:00

本文是如何在Apache httpd 中实现 HTTP/2 的教程。这一特性已经可以在生产环境中使用。

HTTP/2 协议

HTTP/2 是世界上最成功的应用层协议 - HTTP 的演进版。它关注于网络资源的更有效利用。它并没有改变 HTTP 的基本原理,语义。仍然是请求、响应及 header 等。因此,如果你已经了解过 HTTP/1,  你就已经懂了 HTTP/2 的 95%。网上有许多关于 HTTP/2 以及它如何运作的文章。最为规范的当然是 RFC 7540(同时也是最容易读的格式)。

不过,最好还是不要在最开始的时候就去读。最好还是先去明白它要做的是什么,然后再去读 RFC 了解它是怎么工作的。

首先,需要先了解一些新术语:

  • HTTP/2 是一个二进制协议(binary protocol)
  • 不同于 HTTP 1.1 的普通文本 plain text。
  • h2 指的是 HTTP/2 over TLS (protocol negotiation via ALPN).
  • h2c 是 HTTP/2 over TCP.
  • frame (帧?)是一个 HTTP/2 连接的最小单位,它是按照 frame 类型由 header 和八位字节的变长系列组成。详情可以参见官方文档。
  • stream 是 HTTP/2 连接内的一个双向的 frame 流。在 HTTP 1.1 中对应的概念是一个请求/响应信息交换。
  • HTTP/2 可以在同一个 TCP 连接上实现多个流(multipule streams)[即多路复用],以避免 HTTP 1.1 中经典的慢请求阻塞慢并避免为每个请求/响应重建 TCP 连接(HTTP 1.1 中的 KeepAlive 补丁部分解决了这一问题,但没有完全解决)。

Apache httpd 中的 Apache

HTTP2 是由 Apache 自己的 httpd 模块实现,叫做 mod_http2。它实现了 RFC7540 中所描述的一整套特性,并支持明文HTTP/2(http:),同时支持加密连接(https:)。明文叫 h2c,加密则是 h2。h2c 允许直接模式和 upgrade 模式:通过初始的 HTTP/1 请求连接。

HTTP2 的一个新特性是服务端推送。详情查看 RFC 文档对应段落。

编译支持 HTTP/2 的 httpd

mod_http2 使用 nghttp2 库作为它的实现基础。 要编译 mod_http2,你至少需要在你的系统上安装 libnghttp2 的 1.2.1 以上版本。

当你配置 ./configure 你的 Apache httpd 资源树时,你需要使用 --enable-http2 作为额外的参数,以激活该模块的安装。如果你的 libnghttpd2 存放在非通常位置(无论在系统何处),你可以使用 --with-nghttp2=<path> 配置该路径。

虽然这对大部分人都是有效的,还是有人喜欢在该模块中静态链接到 nghttp2。可以使用 --enable-http2-staticlib-deps,它的原理和将 openssl 静态链接到 mod_ssl 相似。 

说到 SSL,你需要了解大部分浏览器只通过 https 连接 HTTP/2,因此你需要支持 SSL 的服务器。不仅如此,你还需要支持 ALPN 扩展的 SSL 库。如果你用的是 OpenSSL 库,你需要用 v1.0.2 以上的版本。