Spring Boot配置Tomcat额外HTTPS端口无法正常工作问题
问题:Spring Boot额外HTTPS端口无法正常协商SSL,仅支持HTTP访问
问题现象
在Spring Boot 2.7.5中配置了额外的HTTPS端口19280,但向该端口发送HTTPS请求时无法正常通信,仅HTTP请求能得到响应。主HTTPS端口9280可正常使用。
测试结果
- HTTPS请求报错:
$ curl --insecure -H "Accept: application/json" -H "Content-Type: application/json" -X GET "https://localhost:19280/app/api/public"
响应:
curl: (35) LibreSSL/3.3.6: error:1404B42E:SSL routines:ST_CONNECT:tlsv1 alert protocol version
后端错误日志:
java.lang.IllegalArgumentException: Invalid character found in method name [0x160x030x010x01(0x010x000x01$0x030x030\90xe9}0xef0x980x970x1b+0x820x0f0xc10xbc0xde0x8370xfceI0xdey0x100x1f0x99vJ0xa50x7f_0xd9Y ]. HTTP method names must be tokens
- HTTP请求正常响应:
$ curl --insecure -H "Accept: application/json" -H "Content-Type: application/json" -X GET "http://localhost:19280/app/api/public"
响应:
Hello Customer (public)
应用启动日志显示已开启两个HTTPS端口:
INFO 2023-06-06/17:08:18/GMT+05:30 [app-rest-api] (TomcatWebServer.java:220) (start) Tomcat started on port(s): 9280 (https) 19280 (https) with context path '/app'
问题原因
配置额外Tomcat Connector时,仅设置了scheme="https"和添加了SSLHostConfig,但未启用SSL功能且未指定正确的协议类型。Tomcat的Connector默认是HTTP模式,此时它会把HTTPS请求的SSL握手数据当作HTTP请求报文解析,从而抛出"无效方法名"的错误。
修复方案
修改PublicPortConfig中的Connector配置,明确启用SSL并指定正确的协议:
@Configuration public class PublicPortConfig { private static final Logger logger = LogManager.getLogger(PublicPortConfig.class); @Value("${server.port.public:19280}") private int port; @Bean @ConditionalOnProperty(name = "server.port.public") public WebServerFactoryCustomizer<TomcatServletWebServerFactory> publicServletContainerCustomizer ( ServerProperties serverProperties) { logger.info("Configuring public port: {}", port); return tomcat -> { // 指定支持SSL的NIO协议 Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol"); connector.setPort(port); connector.setScheme("https"); // 启用SSL connector.setSSLEnabled(true); // 标记该端口为安全端口(用于重定向等场景) connector.setSecure(true); SSLHostConfig sslHostConfig = new SSLHostConfig(); sslHostConfig.setCertificateKeystoreFile(serverProperties.getSsl().getKeyStore()); sslHostConfig.setCertificateKeyPassword(serverProperties.getSsl().getKeyStorePassword()); sslHostConfig.setCertificateKeystoreType(serverProperties.getSsl().getKeyStoreType()); // 可选:指定支持的SSL协议,避免协议版本不兼容 sslHostConfig.setProtocols("TLSv1.2,TLSv1.3"); connector.addSslHostConfig(sslHostConfig); tomcat.addAdditionalTomcatConnectors(connector); }; } }
关键修改点
- 创建Connector时指定支持SSL的协议实现:
new Connector("org.apache.coyote.http11.Http11NioProtocol") - 添加
connector.setSSLEnabled(true):明确启用Connector的SSL功能 - 添加
connector.setSecure(true):标记端口为安全端口,符合HTTPS的语义 - 可选:通过
sslHostConfig.setProtocols指定支持的TLS版本,解决协议版本不兼容问题
验证
重启应用后,再次使用HTTPS请求测试:
$ curl --insecure -H "Accept: application/json" -H "Content-Type: application/json" -X GET "https://localhost:19280/app/api/public"
应正常返回:Hello Customer (public)
内容的提问来源于stack exchange,提问作者Anand
相关产品推荐
相关产品推荐

