如何将主机名重定向至FQDN?Spring Boot HTTPS场景
实现Spring Boot非FQDN到FQDN的强制重定向
我之前刚好搞定过一模一样的场景——用自签HTTPS的Spring Boot服务,要把所有短主机名的访问都跳转到带域名的FQDN上。下面给你两个靠谱的方案,都不用额外加Nginx这类反向代理,纯Spring Boot原生实现:
前提准备
先确认你的配置文件(比如application.properties/application.yml)已经配置好这几个关键参数:
# 短主机名 app.hostname=mymachine # 域名后缀 app.domain=mydomain.com # 你的HTTPS端口 server.port=8888 server.ssl.enabled=true # 自签证书的其他配置(比如key-store路径、密码等) server.ssl.key-store=classpath:keystore.p12 server.ssl.key-store-password=yourpassword server.ssl.key-store-type=PKCS12
方案一:用Spring MVC拦截器(推荐,适合Web应用)
这个方案适合基于Spring MVC的应用,能精准控制哪些路径需要重定向,也容易维护:
- 创建一个拦截器类,注入配置的主机名和域名,在请求处理前判断是否需要重定向:
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; @Component public class FqdnRedirectInterceptor implements HandlerInterceptor { @Value("${app.hostname}") private String shortHostname; @Value("${app.domain}") private String domain; @Value("${server.port}") private int serverPort; private final String fqdn; // 初始化FQDN public FqdnRedirectInterceptor(@Value("${app.hostname}") String shortHostname, @Value("${app.domain}") String domain) { this.fqdn = shortHostname + "." + domain; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String requestHost = request.getServerName(); // 如果请求的主机名不是FQDN,且是我们配置的短主机名(避免误跳转到其他合法域名) if (!fqdn.equalsIgnoreCase(requestHost) && shortHostname.equalsIgnoreCase(requestHost)) { // 拼接完整的FQDN URL,保留原请求的路径和参数 String redirectUrl = String.format("https://%s:%d%s%s", fqdn, serverPort, request.getRequestURI(), request.getQueryString() != null ? "?" + request.getQueryString() : ""); // 301永久重定向(如果是临时需求可以用302) response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); response.setHeader("Location", redirectUrl); return false; // 终止后续请求处理 } return true; // 正常放行 } }
- 注册这个拦截器到Spring MVC配置:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebMvcConfig implements WebMvcConfigurer { private final FqdnRedirectInterceptor fqdnRedirectInterceptor; @Autowired public WebMvcConfig(FqdnRedirectInterceptor fqdnRedirectInterceptor) { this.fqdnRedirectInterceptor = fqdnRedirectInterceptor; } @Override public void addInterceptors(InterceptorRegistry registry) { // 拦截所有请求路径 registry.addInterceptor(fqdnRedirectInterceptor).addPathPatterns("/**"); } }
方案二:用Servlet Filter(更底层,适合所有请求)
如果你的应用有静态资源或者非MVC的请求(比如Actuator端点),用Filter会更全面,覆盖所有进入Tomcat的请求:
- 创建Filter类:
import jakarta.servlet.*; import jakarta.servlet.annotation.WebFilter; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import java.io.IOException; @Component @WebFilter(urlPatterns = "/*") @Order(1) // 设置优先级,确保这个Filter最先执行 public class FqdnRedirectFilter implements Filter { @Value("${app.hostname}") private String shortHostname; @Value("${app.domain}") private String domain; @Value("${server.port}") private int serverPort; private String fqdn; @Override public void init(FilterConfig filterConfig) throws ServletException { this.fqdn = shortHostname + "." + domain; } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; String requestHost = httpRequest.getServerName(); if (!fqdn.equalsIgnoreCase(requestHost) && shortHostname.equalsIgnoreCase(requestHost)) { String redirectUrl = String.format("https://%s:%d%s%s", fqdn, serverPort, httpRequest.getRequestURI(), httpRequest.getQueryString() != null ? "?" + httpRequest.getQueryString() : ""); httpResponse.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); httpResponse.setHeader("Location", redirectUrl); return; } chain.doFilter(request, response); } @Override public void destroy() { // 无需清理资源 } }
注意事项
- 301 vs 302重定向:如果是永久的域名规范,用301(永久重定向),搜索引擎会更新索引;如果只是临时测试,用302(临时重定向)。
- 自签证书的信任问题:重定向后用户浏览器还是会提示证书不安全,这个是自签证书的固有问题,生产环境建议用CA颁发的证书。
- 端口处理:如果你的HTTPS用的是默认443端口,可以去掉URL里的
:8888,代码里可以加个判断:serverPort == 443 ? "" : ":" + serverPort。 - 避免无限重定向:代码里已经判断了只有请求主机是配置的短主机名才会重定向,所以不会出现循环跳转的问题。
内容的提问来源于stack exchange,提问作者spring5150
相关产品推荐
相关产品推荐

