Spring Boot+Tomcat9.0.14同时启用HTTP1.1与HTTP2的兼容问题
解决Spring Boot + Tomcat 9同时支持HTTP/2和HTTP/1.1的问题
看起来你的核心问题是已经在Spring Boot应用中启用了HTTP/2 over SSL,但HTTP/1.1客户端请求时出现连接异常,服务器无法正常响应。这是Tomcat配置HTTP/2时常见的小坑,下面一步步帮你解决:
一、确认核心配置的完整性
首先确保application.properties里同时配置完整的SSL参数和HTTP/2启用开关,这是双协议兼容的基础:
# SSL基础配置(替换为你的证书信息) server.port=8443 server.ssl.key-store=classpath:your-keystore.jks server.ssl.key-store-password=your-password server.ssl.key-store-type=JKS server.ssl.key-alias=your-key-alias server.ssl.enabled-protocols=TLSv1.2,TLSv1.3 # HTTP/2要求TLS 1.2及以上版本 # 启用HTTP/2 server.http2.enabled=true
注意:HTTP/2 over TLS依赖ALPN(应用层协议协商),Java 9及以上版本已经内置ALPN支持,你当前的Java版本没问题,不需要额外依赖。
二、自定义Tomcat连接器强制双协议支持
虽然Spring Boot默认应该让Tomcat同时兼容HTTP/1.1和HTTP/2,但自动配置偶尔会有遗漏。我们可以显式自定义Tomcat连接器,确保双协议都能被处理:
创建一个Spring配置类:
import org.apache.catalina.connector.Connector; import org.apache.coyote.http11.Http11NioProtocol; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.stereotype.Component; @Component public class TomcatHttp2Config implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> { @Override public void customize(TomcatServletWebServerFactory factory) { factory.addConnectorCustomizers((Connector connector) -> { Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler(); // 显式启用HTTP/2支持 protocol.setHttp2(true); // 限定SSL协议版本为HTTP/2兼容的类型 protocol.setSslEnabledProtocols("TLSv1.2,TLSv1.3"); // 指定连接器为NIO类型,同时支持HTTP/1.1和HTTP/2 connector.setProtocol("org.apache.coyote.http11.Http11NioProtocol"); }); } }
这个配置会强制Tomcat的NIO连接器通过ALPN自动协商客户端支持的协议版本,同时处理HTTP/1.1和HTTP/2请求。
三、排查客户端侧的配置问题
如果服务器配置没问题,但客户端仍报错,可能是客户端本身的配置问题:
1. Java 9 HTTP/1.1客户端
如果服务器用的是自签名证书,HTTP/2客户端可能已经信任了证书,但HTTP/1.1客户端没配置信任逻辑。可以添加临时信任配置(仅测试环境使用,生产环境请用合法证书):
// 创建信任所有证书的SSL上下文(测试用) SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, new TrustManager[]{new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) {} @Override public void checkServerTrusted(X509Certificate[] chain, String authType) {} @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } }}, new SecureRandom()); // 构建HTTP/1.1客户端 HttpClient httpClient = HttpClient.newBuilder() .version(HttpClient.Version.HTTP_1_1) .sslContext(sslContext) .build();
2. Apache HttpClient 4.5.x
Apache HttpClient默认使用HTTP/1.1,但Expect: 100-continue请求头可能导致服务器无响应,可以关闭这个配置:
// 配置请求参数,关闭Expect:100-continue RequestConfig requestConfig = RequestConfig.custom() .setConnectTimeout(5000) .setSocketTimeout(5000) .setExpectContinueEnabled(false) .build(); // 构建HttpClient CloseableHttpClient httpclient = HttpClients.custom() .setDefaultRequestConfig(requestConfig) .setConnectionManager(pool) .build();
四、验证配置是否生效
重启Spring Boot应用后,用以下方式验证双协议支持:
- 测试HTTP/1.1:
curl -v --http1.1 https://localhost:8443/your-endpoint - 测试HTTP/2:
curl -v --http2 https://localhost:8443/your-endpoint
如果两者都能正常返回响应,说明配置成功了。
内容的提问来源于stack exchange,提问作者Sanjeev




