通过Eventlet从WSGI应用获取客户端IP地址
我现在正在用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)