Bootstrap

https 被redirect成了http

一、https 被redirect成了http

近期项目中踩到一个坑,记录下来,以免后面再踩。

背景:

目前mqrc项目并不是全站的https,而是仅在F5上配置了https,其架构大致下面这样(这里先省略架构中的apache):

.
                 浏览器
                  |
                  |(https)
            F5 (LoadBalance)               外网
   -----------------------------------------
            |      |      |                内网
            |(http)|(http)|(http) 
            |      |      |
            web   web    web
           应用1  应用2  应用3

也就是说https加密,仅限于浏览器到F5之间,而对web应用来说,所有的请求都是http的,这样如果应用中使用sendRedirect的请求,将会被转发到http。比如该项目中,在filter里的sendRedirect,原先的写法:

// 跳转到登陆页面         
httpServletResponse.sendRedirect(httpServletRequest.getContextPath()+"/login");

或者spring MVC中的写法:

//跳转到登录页面
return "redirect:/login";

以上两种写法,当浏览器访问浏览器访问 https://bu.egtcp..com/index 时,其实相当于发了两次请求,第二次浏览器会访问到 http://bu.egtcp..com/login。

解决方案:

a、跳转的时候url使用绝对地址,而不是相对地址

String url = "/login";
// 将相对地址转换成https的绝对地址
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse)resp;
String scheme = request.getScheme();
String serverName = request.getServerName();
int port = request.getServerPort();
String contextPath = request.getContextPath();
String servletPath = request.getServletPath();
String queryString = request.getQueryString();

StringBuilder sbd = new StringBuilder();
// 强制使用https
sbd.append("https").append("://").append(serverName)
if(port != 80 && port != 443) {
    sbd.append(":").append(port);
}
if(contextPath != null) {
    sbd.append(contextPath);
}
if(servletPath != null) {
    sbd.append(servletPath);
}
sbd.append(url);
if(queryString != null) {
    sbd.append(queryString);
}

// 绝对地址
response.sendRedirect(sbd.toString());

可以的参考Spring Security的 org.springframework.security.web.util.RedirectUrlBuilder 代码。

b、使用forward方法

在servlet中使用RequestDispatcher的forward方法,它与sendRedirect的主要区别在于forward相当于一次请求,然后服务器端内部,以方法调用的方式转到目标地址。写法如下:

// 跳转到登陆页面         
RequestDispatcher view = servletRequest.getRequestDispatcher("/login");
view.forward(servletRequest,servletResponse);

不过使用forward方法,地址栏中看到的只有一个地址,比如https://intlapppdev.95516.com/portal/index,服务器返回了login.jsp页面,但浏览器地址栏没有改变。

c、 在响应信息中设置HTTP状态码和location头信息

进行URL重定向时,服务器设置HTTP状态码和location头信息,当状态码为302时,表明资源位置临时发生了改变,需要进行重定向,location头信息标识了资源转向的位置,该地址写相对地址。写法如下:

//跳转到登录页面
httpServletResponse.setStatus(302);//或者303,兼容http1.1
httpServletResponse.setHeader("location", httpServletRequest.getContextPath()+"/login");

d、 spring mvc中,可以直接配置,将redirectHttp10Compatible属性设为false。如下:

<!-- redirectHttp10Compatible:解决https环境下使用redirect重定向地址变为http的协议,无法访问服务的问题,设置为false,即关闭了对http1.0协议的兼容支持
<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>

事实上,翻一翻spring底层的源码,可以看到,当redirectHttp10Compatible设为false的时候,处理方法也和上面3中提到的方法一致。设置了response头中的location和状态码。

e、 还有可以在Apache设置https反向代理,解决该问题。

 

 

参考链接:

https://blog.csdn.net/zhuye1992/article/details/80496151

https://blog.51cto.com/qiangsh/1891771

;