Spring MVC“ redirect:”前缀始终重定向到http —如何使其保留在https上?

Spring MVC “redirect:” prefix always redirects to http — how do I make it stay on https?

我自己解决了这个问题,但是花了很长时间才发现这样一个简单的解决方案,所以我认为应该在此处进行记录。

我有一个带有InternalResourceViewResolver的典型Spring 3 MVC设置:

1
2
3
4
5
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
  <property name="prefix" value="/" />
  <property name="suffix" value=".jsp" />
</bean>

我的控制器中有一个非常简单的处理程序方法,但在此示例中,我将其简化了很多:

1
2
3
4
@RequestMapping("/groups")
public String selectGroup() {
    return"redirect:/";
}

问题是,如果我浏览到https://my.domain.com/groups,重定向后我将最终到达http://my.domain.com/。 (实际上,我的负载均衡器将所有http请求重定向到https,但是对于那些已打开此类警报的人,这只会导致多个浏览器警报,类型为"您正在离开/进入安全连接"。)

所以问题是:当原始请求使用的是那种方法时,如何使Spring重定向到https?


简短的答案是,将InternalResourceViewResolver的redirectHttp10Compatible属性设置为false:

1
2
3
4
5
6
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
  <property name="prefix" value="/" />
  <property name="suffix" value=".jsp" />
  <property name="redirectHttp10Compatible" value="false" />
</bean>

您可以按照每个请求来执行此操作,方法是让处理程序方法返回View而不是String,然后自己创建RedirectView并调用setHttp10Compatible(false)

(原来是罪魁祸首是HttpServletResponse.sendRedirect,RedirectView用于HTTP 1.0兼容的重定向,但不是这样。我想这意味着它取决于您的servlet容器的实现(?);我在Tomcat和Jetty中都观察到了这个问题。 )


如果您在代理服务器后面运行,Spring Boot为此提供了一个基于配置的解决方案,只需将这两个属性添加到您的application.properties文件中:

1
2
server.tomcat.remote_ip_header=x-forwarded-for
server.tomcat.protocol_header=x-forwarded-proto

这对我有用,将原本没有变化的spring-boot-sample-web-ui部署到https负载均衡器后面的Elastic Beanstalk。没有这些属性,MessageController的第68行上的重定向默认为http并挂起。

希望这可以帮助。


对我有用的是将其添加到application.properties server.tomcat.use-relative-redirects=true

所以当你有:

1
2
3
public function redirect() {
  return"redirect:/"
}

如果没有server.tomcat.use-relative-redirects,它将添加Location标头,例如:http://my-host.com/
使用server.tomcat.use-relative-redirects它将看起来像:/
因此,从浏览器角度来看,它将相对于当前页面。


你确定吗?

查看代码似乎没有什么区别。这两个变体都调用response.encodeRedirectURL(targetUrl),请参见RedirectView的388行:

1
2
3
4
5
6
7
8
9
if (http10Compatible) {
    // Always send status code 302.
    response.sendRedirect(response.encodeRedirectURL(targetUrl));
}
else {
    HttpStatus statusCode = getHttp11StatusCode(request, response, targetUrl);
    response.setStatus(statusCode.value());
    response.setHeader("Location", response.encodeRedirectURL(targetUrl));
}

我遇到了同样的问题,但是它是由在负载均衡器后面设置tomcat触发的。负载平衡器执行SSL握手,然后转发给tomcat一个普通的http连接。

解决方案是在您的负载均衡器中发送一个特殊的Http标头,以便tomcat可以"信任"此连接。使用Servlet过滤器应设置response.isSecure标志。然后覆盖RedirectView以查看response.isSecure是否正确处理。

我把这个解决方案简短了,因为我不确定它是否解决了这个问题。


从Spring Boot 2.1开始,您必须在application.properties中添加以下配置:

1
server.use-forward-headers=true

application.yml

1
2
server:
  use-forward-headers: true

我在文件server.xml中为port="80"连接器添加了scheme="https"

1
2
<Connector port="80" protocol="HTTP/1.1" URIEncoding="UTF-8"
connectionTimeout="20000" redirectPort="443" scheme="https" />

如果使用springmvc,则可以尝试以下操作:

1
modelAndView.setView(new RedirectView("redirect url path", true, false));