如何使用Python Bottle框架获取客户端IP地址

8
我需要使用Python获取客户端IP地址。我尝试过以下代码,但在服务器上无法正常工作:
from socket import gethostname, gethostbyname 
ip = gethostbyname(gethostname()) 
print ip

在服务器上,每次都会得到'127.0.0.1'。有没有办法找到客户端的IP地址?


有没有类似于nginx的中间服务,可以接收来自客户端的外部连接,并将HTML请求转发到Bottle? - Luka Rahne
@LukaRahne 我也遇到了同样的问题,当Apache将请求转发给Bottle时:http://stackoverflow.com/questions/36954669/apache-python-bottle-visitor-ip-always-refers-to-127-0-0-1 你有什么想法吗? - Basj
3个回答

16

你正在获取你的服务器的IP地址,而不是你的服务器的客户端

你需要查看请求的REMOTE_ADDR,像这样:

from bottle import Bottle, request

app = Bottle()

@app.route('/hello')
def hello():
    client_ip = request.environ.get('REMOTE_ADDR')
    return ['Your IP is: {}\n'.format(client_ip)]

app.run(host='0.0.0.0', port=8080)

编辑 #1: 一些人发现,对于他们来说,REMOTE_ADDR 的值始终是相同的 IP 地址(通常为 127.0.0.1)。这是因为他们在代理(或负载均衡器)后面。在这种情况下,客户端原始的 IP 地址通常存储在头部字段 HTTP_X_FORWARDED_FOR 中。以下代码可以适用于任何情况:

@app.route('/hello')
def hello():
    client_ip = request.environ.get('HTTP_X_FORWARDED_FOR') or request.environ.get('REMOTE_ADDR')
    return ['Your IP is: {}\n'.format(client_ip)]

编辑 #2 : 感谢@ArtOfWarfare的评论,我了解到根据PEP-333,REMOTE_ADDR并不是必需的。一些观察结果:

REMOTE_ADDR变量必须设置为发送请求到服务器的客户端的网络地址。

  • 然而,PEP-333并没有明确要求使用HTTP_REMOTE_ADDR,只是强调了这个(重点在于我):

一个服务器或网关应该尝试提供所有适用的其他CGI变量。

  • 我熟悉的所有(虽然很少)Web框架都会设置HTTP_REMOTE_ADDR。就我看来,这是一个事实上的“标准”。但从技术上讲,可能有差异。

1
我有同样的问题,REMOTE_ADDR总是给出127.0.0.1: http://stackoverflow.com/questions/36954669/apache-python-bottle-visitor-ip-always-refers-to-127-0-0-1 - Basj
这是如何工作的?谁设置了名为REMOTE_ADDR的变量,它是如何传输的?它是由客户端软件、客户端硬件、中间路由器、wsgi还是其他方式设置的?如果这个GET请求来自像Firefox这样的普通浏览器,或者来自Python requests脚本,会有什么区别吗?PEP 333没有提到它,所以我很好奇REMOTE_ADDR在哪里被指定/标准化/记录? - ArtOfWarfare
1
@ArtOfWarfare 谢谢,我没有意识到这不是标准的。请看我的编辑,以回应您提出的观点。如果您愿意,我很乐意重新编辑以获得更多的清晰度。 - ron rothman

7

服务器可能位于代理后面。请使用以下内容以支持代理和转发:

request.environ.get('HTTP_X_FORWARDED_FOR') or request.environ.get('REMOTE_ADDR')

为什么要用 or?你能解释一下吗,它是一个位运算符 or 吗?还是只是为了处理 HTTP_X_FORWARDED_FOR 为空的情况? - Basj
2
没错。有时候,HTTP_X_FORWARDED_FOR是空的,但是检查代理IP是很重要的。 - Farshid Ashouri

2
如果你想获取外部IP地址,你需要从外部来源获取,例如whatismyip.com或提供api的其他地方。如果这是你要找的,可以看看Requests模块。 http://docs.python-requests.org/

4
我认为你没有理解问题。 (或者可能是我自己没理解。:)) - ron rothman
你知道吗,我看到了他试图使用的代码并得出了结论。眼力不错。 - blasko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接