首先,nginx必定会设置一个Header传送过来真实的IP

nginx.conf

server {

  proxy_set_header X-Real-IP $remote_addr;
location / {
proxy_pass http://192.168.7.206:8888/;
}
}

然后,tornado的Handler里面进行如下处理:

class Handler(BaseRequestHandler):

    def post(self):
self.get() def get(self):
remote_ip = self.request.headers.get("X-Real-Ip", "")

此处,下面两行其实是没有任何区别的,ng的header到了tornado会做一次统一整理(具体可以参考class HTTPHeaders)。

ip = self.request.headers.get("X-Real-Ip", "")
ip = self.request.headers.get("X-Real-IP", "")

然后,就可以了。


但是,这里为啥还有但是呢?这段日志还有奇怪的地方,它记录的还不对,这个是tornado的默认日志。

[I 150806 14:54:21 web:1811] 200 POST / (192.168.7.62) 2.74ms

看tornado==v4.2.0的代码web.py文件某处一定有如下类似的部分:

    def log_request(self, handler):
"""Writes a completed HTTP request to the logs. By default writes to the python root logger. To change
this behavior either subclass Application and override this method,
or pass a function in the application settings dictionary as
``log_function``.
"""
if "log_function" in self.settings:
self.settings["log_function"](handler)
return
if handler.get_status() < 400:
log_method = access_log.info
elif handler.get_status() < 500:
log_method = access_log.warning
else:
log_method = access_log.error
request_time = 1000.0 * handler.request.request_time()
log_method("%d %s %.2fms", handler.get_status(),
handler._request_summary(), request_time)

这块其实就是日志的实现,_request_summary 又是啥?

    def _request_summary(self):
return "%s %s (%s)" % (self.request.method, self.request.uri,
self.request.remote_ip)

后续继续看,发现,self.request.remote_ip这个其实就是tornado针对客户端IP做的快捷访问,这里为啥不对呢?

原来要在初始化listen的时候设置一个参数:

def main():
app = Application()
app.listen(options.port, xheaders = True)

产生的效果就是

[I 150806 13:52:53 web:1908] 200 POST / (192.168.7.214) 1.86ms

真实IP反映到Tornado的基础日志里了。

具体实现追踪可以查看 tornado\httpserver.py 中的相关代码。

class _ServerRequestAdapter(httputil.HTTPMessageDelegate):

    def headers_received(self, start_line, headers):
if self.server.xheaders:
self.connection.context._apply_xheaders(headers) class _HTTPRequestContext(object): def _apply_xheaders(self, headers):
"""Rewrite the ``remote_ip`` and ``protocol`` fields."""
# Squid uses X-Forwarded-For, others use X-Real-Ip
ip = headers.get("X-Forwarded-For", self.remote_ip)
ip = ip.split(',')[-1].strip()
ip = headers.get("X-Real-Ip", ip)
if netutil.is_valid_ip(ip):
self.remote_ip = ip
# AWS uses X-Forwarded-Proto
proto_header = headers.get(
"X-Scheme", headers.get("X-Forwarded-Proto",
self.protocol))
if proto_header in ("http", "https"):
self.protocol = proto_header def _unapply_xheaders(self):
"""Undo changes from `_apply_xheaders`. Xheaders are per-request so they should not leak to the next
request on the same connection.
"""
self.remote_ip = self._orig_remote_ip
self.protocol = self._orig_protocol

tornado 反向代理后 获取真实客户端IP的更多相关文章

  1. nginx设置反向代理,获取真实客户端ip

    upstream这个模块提供一个简单方法来实现在轮询和客户端IP之间的后端服务器负荷平衡. upstream abc.com { server 127.0.0.1:8080; server 127.0 ...

  2. nginx经过多层代理后获取真实来源ip

    nginx取 $remote_addr 当做真实ip,而事实上,$http_X_Forwarded_For 才是用户真实ip,$remote_addr只是代理上一层的地址 解决方案: 在 http 模 ...

  3. JAVA获取客户端请求的当前网络ip地址(附:Nginx反向代理后获取客户端请求的真实IP)

    1. JAVA获取客户端请求的当前网络ip地址: /** * 获取客户端请求的当前网络ip * @param request * @return */ public static String get ...

  4. NGINX前端代理TOMCAT取真实客户端IP

    nginx前端代理tomcat取真实客户端IP 使用Nginx作为反向代理时,Tomcat的日志记录的客户端IP就不在是真实的客户端IP,而是Nginx代理的IP.要解决这个问题可以在Nginx配置一 ...

  5. nginx+tomcat集群配置(3)---获取真实客户端IP

    前言: 在初步构建的nginx+tomcat服务集群时, 发现webserver获取到的客户端ip都是同一个, 皆为作为反向代理服务的nginx所在的机器IP. 这不太符合我们的基本需求, 为将来的数 ...

  6. ABP vNext 审计日志获取真实客户端IP

    背景 在使用ABP vNext时,当需要记录审计日志时,我们按照https://docs.abp.io/zh-Hans/abp/latest/Audit-Logging配置即可开箱即用,然而在实际生产 ...

  7. 关于nginx反向代理后获取不到客户端的真实ip地址问题

    前段时间在我的网站上用nginx做了一下反向代理,最近发现不能获取客户端ip了,都是拿到的127.0.0.1的本地ip... 通过查资料后,再去看了看我的配置文件,结果发现我没有如下配置: nginx ...

  8. nginx做反向负载均衡,后端服务器获取真实客户端ip(转)

    首先,在前端nginx上需要做如下配置: location / proxy_set_hearder host                $host; proxy_set_header X-forw ...

  9. nginx反向代理如何获取真实IP?

    由于客户端和web服务器之间增加了中间层,因此web服务器无法直接拿到客户端的ip,通过$remote_addr变量拿到的将是反向代理服务器的ip地址. 1.安装--with-http_realip_ ...

随机推荐

  1. 怎么提高sql效率

    1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索 ...

  2. UE4 不能显示中文 解决办法

    UE4 4.11.2 方法步骤: 1.在内容浏览器新建一个字体文件如图: 2.打开刚刚创建的那个字体文件: 选择Offline,会有一个弹出框点击 “是” 接下来就选择你要用到的字体 红色矩形框出的文 ...

  3. jquery怎么获取radio选中的值

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  4. 1.4 云计算的SPI服务模型

    云计算是通过共享资源池的方式来提高资源利用率的.在云计算中,根据其资源池中资源的类别,可以把云计算的服务模型分为三种,即所谓的SPI 模型   应用程序 Software as a Service ( ...

  5. JDBC使用事务实例

    package qddx.JDBC; import java.sql.*; public class useTransaction { public static void main(String[] ...

  6. spring访问静态资源出错,No mapping found for HTTP request with URI xxx/resources/js/jquery.min.js...

    问题:spring访问静态资源出错,No mapping found for HTTP request with URI xxx/resources/js/jquery.min.js... web.x ...

  7. TP中关于自定义类库的添加和使用

    ThinkPHP的类库主要包括公共类库和应用类库,都是基于命名空间进行定义和扩展的.只要按照规范定义,都可以实现自动加载. 类库存放位置:Think目录:系统核心类库Org目录:第三方公共类库demo ...

  8. mysql 的max_connections和max_user_connections 的区别

    ----查看max_user_connections 默认值 MySQL> show variables like 'max_user_connections'; +-------------- ...

  9. 浅析c#中登录窗体和欢迎窗体关闭的问题

    第一次在cnbogs发文章,这次来个很基础的,主要给小白看. 在c#的winform编程中,我们经常会做登录窗体或欢迎窗体,并把他们作为启动窗体. 但是,我们有可能会遇到一些问题. 请看下面的代码: ...

  10. Struts2.3.15.1源码浅析

    Struts2 两大运行主线: 1.初始化主线:初始化主线主要是为Struts2创建运行环境(此处的环境与Struts2身处的Web环境是有区别的),初始化入口StrutsPrepareAndExec ...