Spring Boot 启用 HTTP2

1、概览

HTTP/2 是广泛使用的 HTTP/1.1 协议的后续协议,它通过采用多路复用和 Header 压缩等新功能提高了网络性能。

本文将带你了解如何配置 Spring Boot 应用,以在嵌入式 Tomcat 服务器上启用 HTTP/2。

2、HTTP/2

超文本传输协议(HTTP)是一种在互联网上获取资源的应用协议。HTTP/1.1 于 1997 年 1 月发布,二十多年来为大多数网络提供服务。该版本发现了在某些情况下导致性能缓慢的问题。

HTTP/2 克服了 HTTP/1.1 中的性能问题,具有以下特点:

  • 多路复用 - HTTP/1.1 使用多个连接发送多个请求;多路复用允许通过单个连接发送请求,从而减少资源消耗和延迟
  • Header 压缩 - 如果不进行压缩,由于 TCP 启动速度较慢,通常需要多次往返才能发送 Header;压缩 Header 后,Header 的发送往返次数会减少,大部分时间都能在一次往返内完成
  • 二进制 - 与使用文本编码数据的 HTTP/1.1 相比,HTTP/2 以二进制格式发送数据,以减少解析开销并缩小报文大小。

3、先决条件

HTTP/2 可以通过明文或 TLS 运行。大多数 Web 浏览器不支持明文 HTTP/2,因此建议通过 TLS 运行。

首先要在嵌入式 Web 服务器上启用 SSL。

在控制台中运行以下 keytool 命令来生成一个 keystore,用于存储 SSL/TLS 使用的密钥和证书,并将其放入嵌入式 Tomcat 中。

$ keytool -genkeypair -alias http2-alias -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore keystore.p12 -validity 3650

keytool 会要求我们输入密码,稍后需要将其添加到 Spring Boot 配置中。完成该过程后,keytool 将生成 keystore.p12 文件。

将把该文件复制到 Spring Boot 应用程序下的 resources 文件夹中。

现在,在 application.yml 中添加以下属性,以在嵌入式 Tomcat 中启用 HTTPS:

server:
  ssl:
    enabled: true
    key-store: classpath:keystore.p12
    key-store-password: <your-password> # 替换为你定义的 Keystore 密码
    key-store-type: PKCS12
    key-alias: http2-alias

4、检查响应中的 HTTP 协议版本

默认情况下,Spring Boot 嵌入式 Tomcat 不会启用 HTTP/2 协议来服务请求。

创建一个简单的 Spring Boot REST 端点来验证一下:

@RestController
public class Http2Controller {
    @GetMapping("/http2/echo")
    public String getChatbotResponse(@RequestParam String message) {
        return message;
    }
}

该端点只接受一个请求参数信息,并将其发送回响应体。

启动应用后,就可以在控制台中执行下面的 curl 命令,使用 -http2 参数,通过 HTTP/2 调用端点:

$ curl -I --http2 http://localhost:8080/http2/echo?message=hello

参数 -I 会显示更多信息,如响应中的 HTTP 协议版本。从打印的输出中,可以看到应用返回了:

HTTP/1.1 200

或者,可以使用 Postman 来验证协议版本。Postman 从 11.8 版开始支持 HTTP/2 协议,其中发送 HTTP 请求的协议版本仍为 HTTP/1.1 默认版本。可以在设置选项卡中更改协议版本:

Postman Http2设置

请求发送后,可以从 Postman 控制台的原始日志中找到 HTTP 协议版本:

Postman 控制台的原始日志

即使以 HTTP/2 发送请求,curlPostman 也会返回 HTTP/1.1 响应。

5、Spring Boot 启用 HTTP/2

在 Spring Boot 应用中启用 HTTP/2 有两种方法。

第一个方法是定义一个配置类,将 Http2Protocol 类添加到 Tomcat HTTP connector 中:

@Configuration
public class Http2Config {
    @Bean
    public WebServerFactoryCustomizer<TomcatServletWebServerFactory> getWebServerFactoryCustomizer() {
        return factory -> {
            Connector httpConnector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
            httpConnector.setPort(8080);
            factory.addConnectorCustomizers(connector -> connector.addUpgradeProtocol(new Http2Protocol()));
            factory.addAdditionalTomcatConnectors(httpConnector);
        };
    }
}

该配置类可自定义嵌入式 Tomcat 服务器,并通过向 HTTP connector 添加 Http2Protocol 升级来启用 HTTP/2 支持。

除了现有的使用 SSL 运行 HTTP/2 的端口 8443 外,该配置还打开了一个额外的 HTTP 运行端口 8080。如果不想暴露额外的端口,可以使用其他方法启用 HTTP/2。

第二种方法更简单。只需在 application.yml 中将 server.http2.enabled 属性设置为 true

server:
  http2:
    enabled: true

在应用其中任何一种方法后重启应用,就可以执行相同的 curl 命令来查询 REST 端点;我们可以收到以下响应,显示 HTTP/2 已启用:

HTTP/2 200

如果再次向 Postman 发送请求,就会看到如下响应:

Postmant HTTP2 日志

6、总结

HTTP/1.1 长期以来一直是传递 HTTP 请求的主流协议,而 HTTP/2 提供了更好的资源效率并减少了延迟。这是一个巨大的进步,使其成为现代 Web 应用的重大升级。


Ref:https://www.baeldung.com/spring-boot-http2-tomcat