前言:
  在初步构建的nginx+tomcat服务集群时, 发现webserver获取到的客户端ip都是同一个, 皆为作为反向代理服务的nginx所在的机器IP. 这不太符合我们的基本需求, 为将来的数据挖掘和分析带来了麻烦.
  不过不用担心, 本文将简单介绍其背后的原因和原理, 以及具体的解决方案, ^_^.

原因分析:
  webserver在获取客户端ip时, 默认的方式是通过request.getRemoteAddr(), 这种方式本质是从直连的socket中获取到的.
  因此客户端直连web server服务器, 则获取到的ip即为真实的client ip地址信息. 不过若通过代理, 则直连的ip会被代理服务器的ip所替代.
  
  通过图中的对比, 我们可以清楚的观察到, 在反向代理模式下, 客户端的socket已经被nginx的socket所代替. 若还是按默认的方式来获取客户端ip, 将失去意义.

解决思路:
  nginx是7层代理, 不是lvs的4层代理, 因此不可能在tcp/ip这层做手脚. 只能在http/https这个应用层协议中做文章.
  事实上, 其解决方案是基于约定的方案, 需要各方的配合来完成并实现.
  nginx的策略是: 往http/https请求中, 添加额外的header信息, 以此来完成真实客户端ip的信息传递.
  

nginx配置:
  先来介绍下nginx中的一些内部变量定义.

$host
$remote_addr #来自对端socket的ip地址
$remote_port #来自对端socket的port信息
$proxy_add_x_forwarded_for #http/https请求流经的所有代理的ip

  更详细的nginx内部变量, 请参阅"nginx rewrite 参数和例子".
  在nginx配置中, 需要在location标签下添加如下项:

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

  对于X-Real-IP, 大家肯定容易接受和理解. 但对于X-Forwarded-For, 大家肯定有些疑惑, 这到底是什么鬼, 具体有什么用呢?
  • X-Forwarded-For

简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,只有在通过了HTTP 代理或者负载均衡服务器时才会添加该项。它不是RFC中定义的标准请求头信息,在squid缓存代理服务器开发文档中可以找到该项的详细介绍。
标准格式如下:X-Forwarded-For: client1, proxy1, proxy2, ...
从标准格式可以看出,X-Forwarded-For头信息可以有多个,中间用逗号分隔,第一项为真实的客户端ip,剩下的就是曾经经过的代理或负载均衡的ip地址,经过几个就会出现几个。

  光从定义来看, X-Forward-For只是记录了, 来自客户端所流经的代理服务器的链路路程, 好像没啥作用. 获取真实IP, 通过获取设定的X-Real-IP即可.
  一般情况下, 好像是可行的, 因为是你忽略了, 你的web架构中, nginx代理只有一层. 当web架构中, 存在多层代理服务器时, 使用X-Real-IP会丢失真实的客户端IP, 而X-Forward-For依旧为你保留了真实的客户端ip, 这也为什么后端web server从X-Forward-For中获取client ip, 而不是从X-Real-IP中获取的本质原因.
  

tomcat配置:
  在server.xml的配置中, 对于日志的输入格式和内容默认为:

<!-- Access log processes all example.
    Documentation at: /docs/config/valve.html
    Note: The pattern used is equivalent to using pattern="common" -->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
  prefix="localhost_access_log" suffix=".txt"
  pattern="%h %l %u %t &quot;%r&quot; %s %b" />

  注: 格式pattern="%h %l %u %t &quot;%r&quot; %s %b", 默认等价于pattern="common"

  输出的样例结果为:

127.0.0.1 - - [17/Feb/2016:16:30:39 +0800] "GET / HTTP/1.1" 200 52

  要输出前端nginx传递过来的客户端实际ip, 则需要把格式改为如下:

pattern="%{X-Forwarded-For}i %l %u %t &quot;%r&quot; %s %b"

  这样tomcat的就能利用到新注入的header, 并输出真实客户端ip到日志中去.

webapp的修改:
  在webapp中, 获取ip可以修改如下:

HttpServletRequest request = ...;
String ip = request.getHeader("X-Forwarded-For");

  来代替:

HttpServletRequest request = ...;
String ip = request.getRemoteAddr();

  在结合log4j的使用中, 可以借助MDC/NDC来写入ip地址:
  java代码如下:

HttpServletRequest request = ...;
String ip = request.getHeader("X-Forwarded-For");
MDC.put("ip", ip);

  log4j的配置如下:

log4j.appender.console.layout.ConversionPattern=[%X{ip}] -[%c]-[%p] %m%n

  注意[%X{ip}] 这个自定义项.
  参考博文"log4j获取IP显示在日志中".

总结:
  对于该问题, 网上有很多资料. 这边重复一下, 一方为总结, 一方也觉得有所收获. 权当学习笔记.

公众号&游戏站点:
  个人微信公众号: 木目的H5游戏世界
  
  个人游戏作品集站点(尚在建设中...): www.mmxfgame.com,  也可直接ip访问http://120.26.221.54/.

nginx+tomcat集群配置(3)---获取真实客户端IP的更多相关文章

  1. nginx+tomcat集群配置(4)--rewrite规则和多应用根目录设定思路

    前言: nginx中有一块很重要的概念, 就是rewrite规则. 它会对URL进行修改, 然后进行内部的重定向. rewrite授予了nginx更多的自由, 使得后级服务的接入更加地方便. 本文将简 ...

  2. nginx+tomcat集群配置(1)---根目录设定和多后端分发配置

    前言: 对于javaer而言, nginx+tomcat集群配置, 已然成了web应用部署的主流. 大公司如此, 小公司亦然. 对于个人开发者而言, 资源有限, 往往多个web应用混部于一台服务器(云 ...

  3. Nginx+Tomcat集群配置

    Nginx+Tomcat集群配置 一台虚拟机作为Nginx服务 两太虚拟机配置Tomcat+jdk环境 Nginx测试 启动: cd usr/local/nginx/sbin ./nginx ---& ...

  4. nginx+tomcat集群配置(2)---静态和动态资源的分离

    前言: 在web性能优化的领域, 经常能听到一个词, 就是静态/动态资源分离. 那静态/动态资源分离究竟是什么呢? 本文不讲文件系统服务, 云存储, 也不讲基于CDN的优化. 就简单讲讲基于nginx ...

  5. Nginx+Memcached+Tomcat集群配置实践(Sticky Session)

    准备工作 创建一个简单的web应用,名为session.其中有两个页面,分别如下所示: 页面login.jsp <%@ page language="java" conten ...

  6. Nginx+Memcached+Tomcat集群配置(MSM--win7 64bit)

    本次主要是在win7 64 上演示操作. web应用构建 Memcached安装配置启动 Tomcat配置 所需jar包 memcached-session-manager 序列化 contextxm ...

  7. 【nginx+tomcat集群】Nginx1.12.2+Tomcat7集群+负载均衡+Session共享

    今天想着将项目优化一下,就想的实现集群分布,在本机测试:利用nginx+tomcat实现 通过上一篇博客(http://www.cnblogs.com/qlqwjy/p/8535235.html),N ...

  8. 160513、nginx+tomcat集群+session共享(linux)

    第一步:linux中多个tomcat安装和jdk安装(略) 第二步:nginx安装,linux中安装nginx和windows上有点不同也容易出错,需要编译,这里做介绍 一.安装依赖 gcc open ...

  9. Nginx+Tomcat集群+session共享

    Nginx+Tomcat集群+session共享 1)安装Nginx 2)配置多个Tomcat,在server.xml中修改端口(端口不出现冲突即可) 3)在nginx.conf文件中配置负载均衡池, ...

随机推荐

  1. C++字符串与转移字符

    先看以下代码: #include<iostream> #include<string> using namespace std; int main() { string str ...

  2. [像黑客一样生活] shell终端听音乐之网易云shell版

    这是一个Python程序,使用Python构建,并以mpg123作为后端.Follow me... 特点: Vim 式的流畅操作,支持快捷键绑定 支持电台.收藏等各种特色功能 支持 OS X 及各类 ...

  3. Zookeeper第一课 安装和配置

    简介: Zookeeper,是Google的Chubby一个开源的实现,是Hadoop的分布式协调服务,它包含一个简单的原语集,来实现同步.配置维护.分集群.命名的服务. zookeeper是一个由多 ...

  4. JS中的各种类型转换规则(转)

    JS中的类型转换非常恶心,大家都懂的,不过该学还是要学. 今天看犀牛书看到了转换规则,总结出来. X转字符串.数字.布尔值 X表示各种类型的值,直接上图: 值 转数字 转字符串 转布尔值 undefi ...

  5. xml资源getStringArray(R.array.xxx)方法

    在res/values/下新建menu_names.xml 代码如下: <?xml version="1.0" encoding="utf-8"?> ...

  6. js 排序Json数组

    由于对用java处理数据需要各种数据类型的转换,非常郁闷,个人更偏向于用js做数据处理,直接上code,希望对你有帮助: function sortJsonArr(jsonArr, sortName, ...

  7. java.lang.UnsupportedClassVersionError: org/apache/maven/cli/MavenCli : Unsupported major.minor version 51

    http://blog.csdn.net/e_wsq/article/details/52100234 一日换了一下MyEclipse,换成2016CI,结果从SVN上下载了一个工程后出现以下错误: ...

  8. vue服务端渲染

    这篇文章写得还蛮好https://segmentfault.com/a/1190000006701796 从官方网站下载了例子看,用es6写的,还好之前看过es6不然都看不懂,正好es6的东西一起熟悉 ...

  9. HashSet其实就那么一回事儿之源码浅析

    上篇文章<HashMap其实就那么一回事儿之源码浅析>介绍了hashMap,  本次将带大家看看HashSet, HashSet其实就是基于HashMap实现, 因此,熟悉了HashMap ...

  10. Android 《第一行代码》 第二章练习代码 ActivityTest

    FirstActivity.java package com.example.activitytest; import android.app.Activity; import android.con ...