反向代理使用https协议,后台tomcat使用http,redirect时使用错误协议的解决办法
2018-02-28 14:47
831 查看
问题描述
今天遇到一个奇怪的现象,原先部署在外网访问的应用某些功能出现了异常错误,用chrome开发者工具调试后发现一个奇怪的错误:意思基本上就是当前页面是https协议加载的,但是这个页面发起了一个http的ajax请求,这种做法是非法的。
现象
进一步分析后发现以下三个现象:在排查代码之后并没有发现代码里有任何写死使用http协议的地方,而后又发现另一个应用也出现了这个情况,两个应用使用的框架分别是struts2和spring,这个问题似乎和框架无关。而后发现原先部署在这两个应用之前的反向代理的协议从原来的http改成了https,但是这两个应用的tomcat并没有跟着升级成https而依旧是http。
经过进一步跟踪请求发现并不是所有请求都出现异常,而只有redirect的地方出现问题,而redirect的时候并没有使用https协议,而依然是http。
推论
结合上面三个现象推论:这个问题和框架无关是tomcat和反向代理协议不一致造成的
问题出在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发现了 Remote IP Valve 的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);
}
}
//....
}
解决办法
在反向代理那里设置一个头X-Forwarded-Proto,值设置成
https。
在tomcat的server.xml里添加这段配置:<Valve className="org.apache.catalina.valves.RemoteIpValve" protocolHeader="X-Forwarded-Proto" />
如此一来
sendRedirect的时候就能够正确的使用协议了。
相关文章推荐
- nginx反向代理tomcat应用,struts2网站程序redirect时导致请求地址错误的解决方法
- 关于"Ueditor 请求后台配置项http错误,上传功能将不能正常使用"的解决办法
- 反向代理Https,Tomcat使用http的问题
- nginx反向代理tomcat,由于客户端输入的端口不一致造成网页basehref错误的问题及解决办法
- .NET版UEditor报请求后台配置项http错误,上传功能无法使用的错误解决
- Chrome强制http定向到https方法(使用google搜索终极解决办法)
- oracle11g安装完成在cmd命令行使用sqlplus登录时提示:ORA-12560: TNS: 协议适配器错误 的解决办法
- iOS9要求网络使用HTTPS协议-解决办法
- (转)IIS tomcat共用80端口解决一个IP多个域名:使用Nginx反向代理方式使两者兼容
- 使用MyEclipse开启Tomcat服务报已被占用错误的解决办法
- 启动tomcat时 错误: 代理抛出异常 : java.rmi.server.ExportException: Port already in use: 1099的解决办法
- https使用HttpWebRequest出现错误:System.IO.IOException: Received an unexpected EOF or 0 bytes from the transport stream.的解决方法
- 【已解决】使用android-async-http网络请求框架出现Header[]不识别错误的解决办法
- 启动tomcat时 错误: 代理抛出异常 : java.rmi.server.ExportException: Port already in use: 1099的解决办法
- 修改端口Tomcat配置https协议、以及http协议自动REDIRECT到HTTPS-java教程
- 在iOS9中,苹果将原http协议改成了https协议,使用 TLS1.2 SSL加密请求数据。如何解决报错
- haproxy1.5.15代理下,使用IE访问url里传输中文参数时错误解决办法.
- 使用Xutils的时候rg.apache.http.client.methods.HttpRequestBase错误的解决办法