在tomcat应用中获得原始IP
Apache/Nginx 通常被放在tomcat前作为http代理。
browser -> apache -> tomcat
但是缺点是丢失了很多原有的网络信息:ip、hostname、protocol(用的是http还是 https)
比如,当java程序想生成http重定向请求的时候会遇到麻烦。因为HTTP头部的Location字段的值必须是绝对URL。重定向的问题勉强可以交给前面的proxy来解决(让apache重写header),但是藏在http body中的各种链接问题就棘手多了。比如当从一个html页面载入一个外部资源时,资源的链接到底是写http的还是https的呢?
通过修改apache和tomcat的配置,可以让这个问题得到较为完美的解决。
首先是要apache把这些丢失的信息通过http header发到后面去。
1. Host字段
HTTP头部的Host字段用来写网站的域名。如果服务器(此处指tomcat)需要支持virtual host,即同一个IP服务多个域名,那么这个字段很重要。
在配置mod_proxy时加上ProxyPreserveHost,就会让apache往后端转发的时候,Host字段依然填它从browser收到的那个域名。
2. Apache默认会发送的字段
默认情况下apache在做http逆向代理时会给后端发送以下字段
X-Forwarded-For client的IP地址
X-Forwarded-Host client所请求的域名,即client发来的的http header中Host字段的值。
X-Forwarded-Server 这台代理服务器(apache)的域名。
3. 需要添加的
纵使有了以上信息,我们还是不知道client用的到底是http还是https访问的apache。所以要加下面这行:
RequestHeader set X-Forwarded-Proto “https” env=HTTPS
这行代码的意思是,如果当前含有“HTTPS”这个环境变量,那么往后端转发请求时,在头部加上X-Forwarded-Proto字段,值为”https”。
类似的还可添加其它信息。如HTTPS/SPDY的具体信息,假如前端用的是spdy,那么当前请求不仅具有HTTPS这个环境变量,还有一个名为SPDY_VERSION的环境变量,它的值就是spdy 的版本号。
RequestHeader set X-SPDY-VERSION “%{SPDY_VERSION}e” env=SPDY_VERSION
等等。其它需要什么添加什么。如果想知道apache有哪些环境变量,把以下三行保存为php文件放到apache上,然后用浏览器访问一下就知道了。
<?php
phpinfo();
?>
其次,是让tomcat理解这些额外的header。
tomcat的Valves,能在收到请求时拦截并修改相应的值。https://tomcat.apache.org/tomcat-7.0-doc/config/valve.html
其中与我在此讨论的问题相关的是org.apache.catalina.valves.RemoteIpValve。它的主要功能是:
1. replaces the apparent client remote IP address and hostname for the request with the IP address list presented by a proxy or a load balancer via a request headers (e.g. “X-Forwarded-For”).
2. replaces the apparent scheme (http/https) and server port with the scheme presented by a proxy or a load balancer via a request header (e.g. “X-Forwarded-Proto”).
简单点说,就是把下面这行代码添加到tomcat的server.xml中的Engine或Host element下。
<Valve className=”org.apache.catalina.valves.RemoteIpValve” remoteIpHeader=”x-forwarded-for” proxiesHeader=”x-forwarded-by” protocolHeader=”x-forwarded-proto” />
然后写个servlet测试下,看看对不对:
public class DumpHeaders extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/plain"); response.setCharacterEncoding("UTF-8"); try(java.io.PrintWriter writer=response.getWriter()){ writer.println("isSecure:"+request.isSecure()); writer.println("server name:"+request.getServerName()); writer.println("remote addr:"+request.getRemoteAddr()); writer.println("headers:"); java.util.Enumeration<String> names=request.getHeaderNames(); while(names.hasMoreElements()){ String headerName=names.nextElement(); java.util.Enumeration<String> values=request.getHeaders(headerName); while(values.hasMoreElements()){ String headerValue=values.nextElement(); writer.println(headerName+"\t"+headerValue); } } } } }
HTTP下:
isSecure:false
server name:www.sunchangming.com
remote addr:60.10.169.130
headers:
host www.sunchangming.com
accept text/html, application/xhtml+xml, */*
accept-language zh-CN
user-agent Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
accept-encoding gzip, deflate
cache-control no-cache
connection Keep-Alive
x-forwarded-host www.sunchangming.com
x-forwarded-server www.sunchangming.com
HTTPS下:
isSecure:true
server name:www.sunchangming.com
remote addr:60.10.169.130
headers:
host www.sunchangming.com
accept text/html, application/xhtml+xml, */*
accept-language zh-CN
user-agent Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
accept-encoding gzip, deflate
cache-control no-cache
x-forwarded-proto https
connection Keep-Alive
x-forwarded-host www.sunchangming.com
x-forwarded-server www.sunchangming.com
建议继续学习:
- tomcat catalina.out日志切割每天生成一个文件 (阅读:8086)
- 使用python来抓取新浪的IP数据 (阅读:7352)
- 获取指定(访客)IP的所有信息,地址、邮政编码、国家、经纬度等的API (阅读:5350)
- 命令行获取主机外网IP,相当于ip138的功能 (阅读:4987)
- 计算机网络协议包头赏析-IP (阅读:4805)
- 当网站使用CDN后获取客户端真实IP的方法 (阅读:4603)
- Tomcat 5源码分析 (阅读:4323)
- nginx在fastcgi模块中转发真实的后端IP (阅读:4026)
- 获取客户端真实IP方法 (阅读:3802)
- Tomcat内存溢出的原因 (阅读:3374)
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:A programmer's life 来源: A programmer's life
- 标签: IP tomcat
- 发布时间:2014-03-19 23:21:27
- [53] IOS安全–浅谈关于IOS加固的几种方法
- [52] 如何拿下简短的域名
- [51] android 开发入门
- [51] 图书馆的世界纪录
- [50] Oracle MTS模式下 进程地址与会话信
- [49] Go Reflect 性能
- [46] 【社会化设计】自我(self)部分――欢迎区
- [46] 读书笔记-壹百度:百度十年千倍的29条法则
- [36] 程序员技术练级攻略
- [29] 视觉调整-设计师 vs. 逻辑