博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
反向代理使用https协议,后台tomcat使用http,redirect时使用错误协议的解决办法...
阅读量:7043 次
发布时间:2019-06-28

本文共 3608 字,大约阅读时间需要 12 分钟。

问题描述

今天遇到一个奇怪的现象,原先部署在外网访问的应用某些功能出现了异常错误,用chrome开发者工具调试后发现一个奇怪的错误:

图片描述

意思基本上就是当前页面是https协议加载的,但是这个页面发起了一个http的ajax请求,这种做法是非法的。

现象

进一步分析后发现以下三个现象:

  1. 在排查代码之后并没有发现代码里有任何写死使用http协议的地方,而后又发现另一个应用也出现了这个情况,两个应用使用的框架分别是struts2和spring,这个问题似乎和框架无关。

  2. 而后发现原先部署在这两个应用之前的反向代理的协议从原来的http改成了https,但是这两个应用的tomcat并没有跟着升级成https而依旧是http。

  3. 经过进一步跟踪请求发现并不是所有请求都出现异常,而只有redirect的地方出现问题,而redirect的时候并没有使用https协议,而依然是http。

推论

结合上面三个现象推论:

  1. 这个问题和框架无关

  2. 是tomcat和反向代理协议不一致造成的

  3. 问题出在redirect上

分析

javax.servlet.http.HttpServletResponse#sendRedirect的javadoc是这么说的:

Sends a temporary redirect response to the client using the specified redirect location URL. This method can accept relative URLs; the servlet container must convert the relative URL to an absolute URL before sending the response to the client. If the location is relative without a leading '/' the container interprets it as relative to the current request URI. If the location is relative with a leading '/' the container interprets it as relative to the servlet container root.

If the response has already been committed, this method throws an IllegalStateException. After using this method, the response should be considered to be committed and should not be written to.

也就是说servlet容器在sendRedirect的时候是需要将传入的url参数转换成绝对地址的,而这个绝对地址是包含协议的。

而后翻阅tomcat源码,发现org.apache.catalina.connector.Response#toAbsolute和绝对地址转换有关:

protected String toAbsolute(String location) {        if (location == null) {            return (location);        }        boolean leadingSlash = location.startsWith("/");        if (location.startsWith("//")) {            // Scheme relative            redirectURLCC.recycle();            // Add the scheme            String scheme = request.getScheme();            try {                redirectURLCC.append(scheme, 0, scheme.length());                redirectURLCC.append(':');                redirectURLCC.append(location, 0, location.length());                return redirectURLCC.toString();            } catch (IOException e) {                IllegalArgumentException iae =                    new IllegalArgumentException(location);                iae.initCause(e);                throw iae;            }

注意到request.getScheme()这个调用,那么问题来了,这个值是什么时候设置的?

在一番google之后发现了,回答推荐使用org.apache.catalina.valves.RemoteIpValve来解决这个问题,查找tomcat发现了的protocolHeader属性的似乎可以解决此问题,进一步在翻看源代码之后发现这么一段跟确认了我的猜测:

public void invoke(Request request, Response response) throws IOException, ServletException {    //...            if (protocolHeader != null) {                String protocolHeaderValue = request.getHeader(protocolHeader);                if (protocolHeaderValue == null) {                    // don't modify the secure,scheme and serverPort attributes                    // of the request                } else if (protocolHeaderHttpsValue.equalsIgnoreCase(protocolHeaderValue)) {                    request.setSecure(true);                    // use request.coyoteRequest.scheme instead of request.setScheme() because request.setScheme() is no-op in Tomcat 6.0                    request.getCoyoteRequest().scheme().setString("https");                    setPorts(request, httpsServerPort);                } else {                    request.setSecure(false);                    // use request.coyoteRequest.scheme instead of request.setScheme() because request.setScheme() is no-op in Tomcat 6.0                    request.getCoyoteRequest().scheme().setString("http");                    setPorts(request, httpServerPort);                }            }    //....    }

解决办法

  1. 在反向代理那里设置一个头X-Forwarded-Proto,值设置成https

  2. 在tomcat的server.xml里添加这段配置:

如此一来sendRedirect的时候就能够正确的使用协议了。

转载地址:http://dlhal.baihongyu.com/

你可能感兴趣的文章
性能测试学习之三—— PV->TPS转换模型&TPS波动模型
查看>>
HDU 4028 The time of a day STL 模拟题
查看>>
Visual Studio 2008中 显示解决方案管理器中的解决方案节点,VS 2010 高级专业版 序列号...
查看>>
SharePoint Framework 构建你的第一个web部件(一)
查看>>
系统设计——权限系统
查看>>
SQL Server-流程控制 6,WaitFor 语句
查看>>
Linux 内核通知链随笔【中】【转】
查看>>
阻塞通信之Socket编程
查看>>
iOS:UIView的CALayer基本演练
查看>>
Moo.fx 超级轻量级的 javascript 特效库
查看>>
代码阅读总结之Fitch and Mather 7.0(自定义字符串缓存页)
查看>>
Ajax发送Post请求
查看>>
android文件导出错误—— failed to pull a selection
查看>>
PHP中的精确计算
查看>>
[CareerCup] 13.9 Aligned Malloc and Free Function 写一对申请和释放内存函数
查看>>
Cookies揭秘 [Asp.Net, Javascript] <转>
查看>>
数据库常见面试题总结
查看>>
jQuery源码分析系列(36) : Ajax - 类型转化器
查看>>
自定义分页标签详解
查看>>
Angularjs 事件指令
查看>>