1 问题
由于网络架构升级,原有http直接访问java 容器(jboss),变成https 访问haproxy 由haproxy 通过http再调用 java 容器。
实际测试发现一个问题,之前项目中使用response.sendRedirect("http://aaa.aaa/aaa");这种方式设置绝对路径跳转的,通过https代理到https访问后都无法访问了,因为jboss访问是http,因此应用拼接的绝对路径也是http的。
2 分析
尝试解决,将绝对路径改为相对路径response.sendRedirect("/aaa"),发现没有效果,抓包看http应答的hearder location还是发送了绝对路径http://aaa.aaa/aaa。
搜索发现原因是由于旧版的http1.1协议不允许location头使用相对路径,因此容器在实现response.sendRedirect时自动做了补全绝对路径。
详见:
Can a redirect to relative path be sent from Java Servlet API?
https://stackoverflow.com/questions/30844807/can-a-redirect-to-relative-path-be-sent-from-java-servlet-api
原因是http1.1必须是一个完整的uri,但在rfc 7231更新时已经允许相对url了
An obsolete version of the HTTP 1.1 specifications (IETF RFC 2616) required a complete absolute URI for redirection.[2] The IETF HTTP working group found that the most popular web browsers tolerate the passing of a relative URL[3] and, consequently, the updated HTTP 1.1 specifications (IETF RFC 7231) relaxed the original constraint, allowing the use of relative URLs in Location headers.[4]
这篇给出的解决方法是手工设置http应答status 和 location头
response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
response.setHeader("Location", url);
另外还可以参考这个文章,这里说了rfc 7231,好像java servlet api 的spec 在4.0 之后支持相对路径
What's the proper way to set the Location header for an HTTP 201 response in a Java Servlet application
https://stackoverflow.com/questions/5043902/whats-the-proper-way-to-set-the-location-header-for-an-http-201-response-in-a-j?rq=1
3 解决
最终的解决方法就是手动设置http status和 location,参考 Java 中Redirect和Forward
https://www.jianshu.com/p/edc69215d7d1
response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
String newLocn = request.getServletContext().getContextPath()+"/redirect";
response.setHeader("Location",newLocn);
HttpServletResponse.SC_MOVED_TEMPORARILY可以直接写成302
ttpServletResponse.SC_MOVED_PERMANENTLY 对应301
301和302是有点区别的,response.sendRedirect 对应302 我就设置的302.目前都正常了。
© 2019, 新之助meow. 原创文章转载请注明: 转载自http://www.xinmeow.com