Spring Boot HTTP转HTTPS时PUT请求出现405错误求助
解决Spring Boot HTTP转HTTPS时PUT请求被转为GET的405错误问题
我太懂这个坑了!之前帮好几个开发者解决过一模一样的问题——Spring Boot配置HTTP转HTTPS后,GET请求正常跳转,但PUT请求一发起就报Request method 'GET' not supported,本质就是默认重定向机制把你的PUT请求硬生生转成GET了,完全不符合预期。
问题根源
当你用配置文件里的server.http.redirect-to-https=true开启自动重定向时,底层依赖的Tomcat默认会对非GET请求使用HTTP 302重定向,而302的默认行为就是将原请求方法转为GET,这就导致后端的PUT接口接收到的是GET请求,自然抛出405错误。
两种可行解决方案
方案一:自定义Tomcat重定向策略(推荐)
核心思路是让Tomcat对非GET请求使用HTTP 307临时重定向,这个状态码会严格保留原请求的方法和请求体,不会做转换。
写一个配置类来定制Tomcat的行为:
import org.apache.catalina.connector.Connector; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class HttpToHttpsRedirectConfig { @Bean public WebServerFactoryCustomizer<TomcatServletWebServerFactory> servletContainerCustomizer() { return factory -> { // 添加HTTP连接器,监听8080端口(根据你的实际HTTP端口调整) factory.addAdditionalTomcatConnectors(createHttpConnector()); // 配置HTTP连接器的重定向目标端口(你的HTTPS端口,比如443) factory.addConnectorCustomizers(connector -> { connector.setRedirectPort(443); connector.setScheme("http"); connector.setSecure(false); }); // 配置上下文,启用307重定向保留原请求方法 factory.addContextCustomizers(context -> { context.addLifecycleListener(event -> { if ("configureStart".equals(event.getType())) { // 关键设置:让Tomcat对非GET请求用307重定向 context.setSendRedirectBody(false); } }); }); }; } private Connector createHttpConnector() { Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL); connector.setPort(8080); // 替换成你的HTTP监听端口 return connector; } }
配置完成后,Tomcat会自动将所有HTTP请求(包括PUT、POST等)以307状态码重定向到HTTPS,完美保留原请求方法和参数。
方案二:自定义Filter手动处理重定向
如果不想修改Tomcat的底层配置,也可以写一个全局Filter,手动拦截HTTP请求并发送307重定向。
首先写Filter类:
import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class HttpsRedirectFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; // 判断当前请求是否为HTTPS if (!req.isSecure()) { // 拼接HTTPS跳转地址 String redirectUrl = "https://" + req.getServerName() + ":443" + req.getRequestURI(); if (req.getQueryString() != null) { redirectUrl += "?" + req.getQueryString(); } // 发送307临时重定向,保留原请求方法 res.setStatus(HttpServletResponse.SC_TEMPORARY_REDIRECT); res.setHeader("Location", redirectUrl); } else { // 已是HTTPS,继续执行后续逻辑 chain.doFilter(request, response); } } @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void destroy() {} }
然后把Filter注册到Spring Boot中:
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FilterConfig { @Bean public FilterRegistrationBean<HttpsRedirectFilter> httpsRedirectFilter() { FilterRegistrationBean<HttpsRedirectFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new HttpsRedirectFilter()); registrationBean.addUrlPatterns("/*"); // 拦截所有请求 registrationBean.setOrder(1); // 确保这个Filter最先执行,优先于其他业务Filter return registrationBean; } }
额外注意事项
- 如果需要永久重定向,可以把307换成HTTP 308永久重定向,但要确保客户端支持这个状态码(现代浏览器和HTTP客户端基本都支持)。
- 确保你的HTTPS基础配置正确,比如在
application.properties/application.yml中已经配置了server.ssl.key-store、server.ssl.key-store-password等必要参数。 - 测试时注意:部分老旧HTTP客户端可能对307/308的处理有问题,但Postman、curl等现代工具都会自动跟随重定向并保留原请求方法。
内容的提问来源于stack exchange,提问作者Dmytro Titov
相关产品推荐
相关产品推荐

