Spring MVC“redirect:”前缀总是redirect到http – 我如何使它保持在https上?

我自己解决了这个问题,但是我花了很长时间才发现了这样一个简单的解决scheme,我认为这是值得logging在这里的。

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

<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> 

我在控制器中有一个非常简单的处理程序方法,但是对于这个例子,我更简化了它:

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

问题是,如果我浏览到https://my.domain.com/groups ,redirect后,我最终在http://my.domain.com/ 。 (实际上,我的负载平衡器会将所有http请求redirect到https,但是这只会导致多个浏览器警报types为“您正在离开/进入安全连接”,而这些警报已打开。

所以问题是:当初始请求使用的时候,如何将springredirect到https?

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

 <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> 

你可以在每个请求的基础上做到这一点,而不是你的处理程序方法返回视图而不是string,并自己创buildRedirectView,并调用setHttp10Compatible(false)

(事实certificate,罪魁祸首是HttpServletResponse.sendRedirect,RedirectView用于HTTP 1.0兼容的redirect,但不是这样,我想这意味着它依赖于你的servlet容器的实现(?);我在Tomcat和Jetty中都观察到了这个问题。 )

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

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

这对我来说就是在https负载平衡器后面部署不变的spring-boot-sample-web-ui到Elastic Beanstalk。 没有这些属性, MessageController第68行的redirect默认为http并挂起。

希望这可以帮助。

你确定?

看看代码,似乎没有区别。 两种变体都调用response.encodeRedirectURL(targetUrl),请参阅RedirectView的第388行:

 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连接。

解决办法是在你的Loadbalancer中发送一个特殊的Http Header,这样tomcat就可以“信任”这个连接。 使用servletfilter应该设置response.isSecure标志。 然后覆盖RedirectView看是否response.isSecure和正确的方式处理它。

我保持这个解决scheme的简短,因为我不确定是否会提出这个问题。