通过Eventlet从WSGI应用获取客户端IP地址

10 投票
1 回答
9749 浏览
提问于 2025-04-17 04:41

我现在正在用Python的Eventlet库写一个基本的调度模型服务器(可以查看这个链接了解更多:http://eventlet.net/doc/)。我看过Eventlet的WSGI文档(链接在这里:http://eventlet.net/doc/modules/wsgi.html),发现eventlet.wsgi.server函数除了记录客户端的IP地址外,还会记录x-forwarded-for这个头信息。

不过,要获取这些信息,得把一个像文件一样的对象(默认是sys.stderr)附加上,然后让服务器把日志输出到这个对象里。

我希望能在应用程序内部直接获取客户端的IP地址,也就是在处理请求的函数里,这个函数有start_response和environ这两个参数。其实,如果environ里有一个键专门用来存放这个信息就太好了。有没有什么简单的方法可以通过environ字典或者类似的方式获取IP地址,而不需要去重定向日志对象呢?

1 个回答

16

你想要的信息在 wsgi 的 environ 里面,具体来说就是 environ['REMOTE_ADDR']

不过,如果有代理服务器在中间,那么 REMOTE_ADDR 就会显示代理服务器的地址,而客户端的真实地址通常会在 HTTP_X_FORWARDED_FOR 里。

这里有一个函数,应该能满足你的需求,适用于大多数情况(感谢 Sævar):

def get_client_address(environ):
    try:
        return environ['HTTP_X_FORWARDED_FOR'].split(',')[-1].strip()
    except KeyError:
        return environ['REMOTE_ADDR']

你可以通过写一个简单的 wsgi 应用程序来轻松查看 wsgi environ 中包含了什么,然后用浏览器访问它,比如:

from eventlet import wsgi
import eventlet

from pprint import pformat

def show_env(env, start_response):
    start_response('200 OK', [('Content-Type', 'text/plain')])
    return ['%s\r\n' % pformat(env)]

wsgi.server(eventlet.listen(('', 8090)), show_env)

然后把这两者结合起来 ...

from eventlet import wsgi
import eventlet

from pprint import pformat

def get_client_address(environ):
    try:
        return environ['HTTP_X_FORWARDED_FOR'].split(',')[-1].strip()
    except KeyError:
        return environ['REMOTE_ADDR']

def show_env(env, start_response):
    start_response('200 OK', [('Content-Type', 'text/plain')])
    return ['%s\r\n\r\nClient Address: %s\r\n' % (pformat(env), get_client_address(env))]

wsgi.server(eventlet.listen(('', 8090)), show_env)

撰写回答