• tornado 反向代理后 获取真实客户端IP


    首先,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的基础日志里了。

    具体实现追踪可以查看 tornadohttpserver.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
  • 相关阅读:
    python_levenshtein 的安装和使用
    接口测试困难
    pycharm修改windows的IP
    Excel读取,修改,新建
    appium混合应用的处理
    冒泡排序
    选择排序
    插入排序
    python中两种退出方式os._exit(),sys.exit()
    二分查找
  • 原文地址:https://www.cnblogs.com/morya/p/4708056.html
Copyright © 2020-2023  润新知