IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

在tomcat应用中获得原始IP

A programmer's life 2014-03-19 23:21:27 累计浏览 3,045 次
本机暂存

   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

同分类推荐文章

  1. 等了十年的 Go 链式管道,终于来了:seq 让你像写 Scala 一样写 Go (2026-06-25 18:38:18)
  2. Go 实验特性详解 (2026-06-21 10:05:27)
  3. amd64 微架构级别对 Go 程序性能提升多少? (2026-06-21 09:38:49)

查看更多 后端 文章 →

建议继续学习

  1. 配置Nginx+uwsgi更方便地部署python应用 (累计阅读 107,164)
  2. 搜狐闪电邮箱的 Nginx/Postfix 使用模式 (累计阅读 33,896)
  3. 记录一个软中断问题 (累计阅读 16,955)
  4. 解析nginx负载均衡 (累计阅读 16,623)
  5. server日志的路径分析 (累计阅读 11,241)
  6. Nginx模块开发入门 (累计阅读 11,172)
  7. 检查nginx配置,重载配置以及重启的方法 (累计阅读 10,897)
  8. Cacti 添加 Nginx 监控 (累计阅读 10,645)
  9. fsockopen 异步处理 (累计阅读 10,345)
  10. 使用Squid缓存视频 (累计阅读 10,339)