Skip to content

同时支持HTTP和HTTPS

可以通过配置两个嵌入式服务器实例来实现:一个用于 HTTP,另一个用于 HTTPS。然而,Spring Boot 的默认配置并不直接支持这种多端口配置。因此,你需要采取一些额外的步骤来设置。

方法 1: 使用两个 Tomcat 实例(通过自定义配置)

这种方法涉及创建两个独立的 Tomcat 容器实例,分别监听不同的端口。这可以通过编写自定义配置类来实现。

步骤

  1. 创建自定义 Tomcat 配置

    编写一个配置类,为 HTTP 和 HTTPS 分别创建 TomcatServletWebServerFactory

    java
    import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
    import org.springframework.boot.web.server.WebServer;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class MultiPortConfig {
    
        @Bean
        public WebServer httpWebServer() {
            TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(8080);
            return factory.getWebServer();
        }
    
        @Bean
        public WebServer httpsWebServer() {
            TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(8443) {
                @Override
                protected void postProcessContext(org.apache.catalina.Context context) {
                    // 自定义 SSL 设置
                }
            };
            factory.addAdditionalTomcatConnectors(createSslConnector());
            return factory.getWebServer();
        }
    
        private Connector createSslConnector() {
            Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
            connector.setScheme("https");
            connector.setSecure(true);
            connector.setPort(8443);
    
            // SSL 配置
            Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
            protocol.setSSLEnabled(true);
            protocol.setKeystoreFile("path/to/keystore.p12");
            protocol.setKeystorePass("your_keystore_password");
            protocol.setKeyAlias("myapp");
    
            return connector;
        }
    }

    这种方法的主要问题是它可能会导致应用程序启动时出现问题,因为 Spring Boot 不期望有多个 WebServer Bean。

方法 2: 使用 server.http.port 属性(推荐)

这是更简单且推荐的方法。你可以在 application.propertiesapplication.yml 中指定 HTTP 端口,并保持 HTTPS 的默认配置。

application.properties 示例

properties
# 默认 HTTPS 端口
server.port=8443
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=your_keystore_password
server.ssl.keyStoreType=PKCS12
server.ssl.keyAlias=myapp

# HTTP 端口
server.http.port=8080

application.yml 示例

yaml
server:
  port: 8443
  ssl:
    key-store: classpath:keystore.p12
    key-store-password: your_keystore_password
    keyStoreType: PKCS12
    keyAlias: myapp
  http:
    port: 8080

请注意,在某些版本的 Spring Boot 中,server.http.port 可能不起作用。如果你遇到问题,可以考虑使用下面的方法。

方法 3: 使用 Reactive 应用程序和 Netty

对于基于 Reactive 的应用程序,你可以利用 Netty 来监听多个端口。不过,这种方法适用于特定场景,不是所有项目都适用。

方法 4: 使用反向代理(如 Nginx 或 Apache)

最灵活且推荐的方式是使用反向代理服务器(如 Nginx 或 Apache),它们能够轻松地将 HTTP 请求转发到 HTTPS。

Nginx 示例配置

nginx
server {
    listen 80;
    server_name yourdomain.com;

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    server_name yourdomain.com;

    ssl_certificate /etc/nginx/ssl/yourdomain.crt;
    ssl_certificate_key /etc/nginx/ssl/yourdomain.key;

    location / {
        proxy_pass http://localhost:8443;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

这种方法不仅简化了应用程序的配置,还提供了更好的灵活性和安全性。例如,你可以更容易地管理证书更新、实施 HSTS 等安全策略。