zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    C++中整型变量的存储大小和范围
    A1038 Recover the Smallest Number (30 分)
    A1067 Sort with Swap(0, i) (25 分)
    A1037 Magic Coupon (25 分)
    A1033 To Fill or Not to Fill (25 分)
    A1070 Mooncake (25 分)
    js 获取控件
    C#代码对SQL数据库添加表或者视图
    JS 动态操作表格
    jQuery取得下拉框选择的文本与值
  • 原文地址:https://www.cnblogs.com/morya/p/4708056.html
Copyright © 2011-2022 走看看