Spring Boot REST Controller:如何为不同端点分别启用HTTP与HTTPS
实现Spring Boot部分端点HTTP、部分HTTPS的方案
你遇到的问题很典型——只配置双连接器会让所有端点同时暴露在两种协议下,核心是要给不同路径加上协议访问限制。下面给你两种靠谱的实现方式,按需选择:
方式一:用Spring Security(推荐,更规范)
如果你的项目已经在用Spring Security,或者愿意引入它,这是最简洁的方案。通过Security规则直接指定不同路径必须使用的协议:
步骤1:先配置双端口(HTTP + HTTPS)
首先确保两个连接器正常工作:
- 在
application.properties里配置HTTPS:
server.port=8443 server.ssl.key-store=classpath:keystore.p12 server.ssl.key-store-password=yourpassword server.ssl.key-store-type=PKCS12 server.ssl.key-alias=youralias
- 编程方式添加HTTP连接器(比如8080端口):
@Configuration public class ServerConfig { @Value("${server.http.port:8080}") private int httpPort; @Bean public ServletWebServerFactory servletContainer() { TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory(); tomcat.addAdditionalTomcatConnectors(createHttpConnector()); return tomcat; } private Connector createHttpConnector() { Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL); connector.setPort(httpPort); // 这里暂不配置全局重定向,后续用Security控制路径级别的协议规则 return connector; } }
步骤2:配置Security的协议规则
创建Security配置类,对不同路径指定协议要求:
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .anyRequest().permitAll() // 根据你的实际权限需求调整,这里先允许所有请求 ) .requiresChannel(channel -> channel // 指定哪些路径必须用HTTPS .requestMatchers("/api/secure/**").requiresSecure() // 指定哪些路径仅允许HTTP .requestMatchers("/api/public/**").requiresInsecure() // 其他路径默认强制HTTPS(可按需修改) .anyRequest().requiresSecure() ); return http.build(); } }
这样一来,访问/api/secure/**的HTTP请求会自动重定向到HTTPS;访问/api/public/**的HTTPS请求会重定向到HTTP,完全符合你的需求。
方式二:自定义Filter(无需Spring Security)
如果不想引入Spring Security,可以写一个自定义过滤器,在请求到达端点前校验协议是否匹配:
步骤1:同样先配置双端口(和方式一的步骤1一致)
步骤2:编写协议校验Filter
@Component public class ProtocolValidationFilter implements Filter { private static final AntPathMatcher PATH_MATCHER = new AntPathMatcher(); // 定义需要HTTPS的路径 private static final List<String> HTTPS_REQUIRED_PATHS = Arrays.asList("/api/secure/**"); // 定义仅允许HTTP的路径 private static final List<String> HTTP_ALLOWED_PATHS = Arrays.asList("/api/public/**"); @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; String requestURI = httpRequest.getRequestURI(); boolean isSecure = httpRequest.isSecure(); // 检查是否是需HTTPS的路径 boolean requiresHttps = HTTPS_REQUIRED_PATHS.stream().anyMatch(path -> PATH_MATCHER.match(path, requestURI)); // 检查是否是仅允许HTTP的路径 boolean requiresHttp = HTTP_ALLOWED_PATHS.stream().anyMatch(path -> PATH_MATCHER.match(path, requestURI)); if (requiresHttps && !isSecure) { // 重定向到HTTPS,或返回403错误(按需选择) String httpsUrl = "https://" + httpRequest.getServerName() + ":8443" + requestURI; httpResponse.sendRedirect(httpsUrl); return; } if (requiresHttp && isSecure) { // 重定向到HTTP,或返回403错误(按需选择) String httpUrl = "http://" + httpRequest.getServerName() + ":8080" + requestURI; httpResponse.sendRedirect(httpUrl); return; } // 协议符合要求,继续执行后续逻辑 chain.doFilter(request, response); } }
这个过滤器会在每个请求到达时校验路径与协议的匹配性,不匹配则重定向到正确协议的端口,也可以根据业务需求改成直接返回403 Forbidden错误。
关键注意点
- 重定向时要确保端口配置正确(HTTPS端口对应
application.properties中的配置,HTTP端口对应编程添加的端口)。 - 测试时分别用两个端口访问不同路径,确认拦截/重定向逻辑是否生效。
- 若项目有其他过滤器,注意调整该协议校验Filter的执行顺序,尽量放在最前面。
内容的提问来源于stack exchange,提问作者Omkar




