fastapi和flask对获取请求IP的探索
一、背景
目的是做一个根据请求获取请求者IP的功能,其应用场景包括:限定每次只有一个客户端登录,判断IP是否在白名单内以及根据IP获取位置信息的功能。
二、思路
思路很简单,就是将请求头的Request的内容提取出来,查阅fastapi和flask手册是有相关的方法的,同时还可以利用nginx代理获取更多的IP信息,接下来就尝试一下。
三、实现
1、FastApi
1)代码
此代码要在云服务器上跑,因为在本地跑 本地访问 ip肯定是127.0.0.0,如果是局域网,那么ip就是局域网内的ip
#!/usr/bin/env python
# coding: utf-8
import uvicorn
from fastapi import FastAPI,Request
app = FastAPI()
@app.get("/ip")
async def root(request: Request):
result={
"ip":request.client.host,
"x-real-ip":request.headers.get("X-Real-Ip",""),
"x-forwarded-for":request.headers.get("x-forwarded-for","")
}
return result
if __name__ == '__main__':
uvicorn.run("fastapiMain:app", host="0.0.0.0", port=5000, log_level="info", reload=True, debug=True,forwarded_allow_ips ='*')
2)访问结果
无Nginx 无代理
无Nginx有代理,这里尝试了浏览器的某插件,这里不能写出来,审核不通过。
有Nginx 无代理
有Nginx有代理
分析一下,这里的x-real-ip和x-forwarded-for是通过nginx加进去的,所以无nginx的时候是空值,这里即使用了代理也获取不到真实的ip可能是因为匿名方式的不同,给出一篇博文,大家可以看看。
2、Flask
1)代码
from flask import Flask, request
app = Flask(__name__)
@app.route('/ip')
def index():
result={
"ip":request.remote_addr,
"X-Real-Ip":request.headers.get("X-Real-Ip",""),
"X-Forwarded-For":request.headers.get("X-Forwarded-For","")
}
return result
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True,port=5000)
2)访问结果
和前面的一样,但是值得注意的是,当使用nginx代理的时候,有一个ip显示了127.0.0.1,其一是访问这个ip的方法的不同,其二我用了反向代理,将8080的端口请求代理到127.0.0.1:5000,因此可能会显示127.0.0.0
3、tronado
1)代码
import tornado.ioloop
import tornado.web
class IndexHandler(tornado.web.RequestHandler):
def set_default_headers(self):
self.set_header('Access-Control-Allow-Origin', "*")
@tornado.gen.coroutine#异步处理
def get(self):
result={
"ip":self.request.remote_ip,
"X-Real-Ip":self.request.headers.get("X-Real-Ip",""),
"X-Forwarded-For":self.request.headers.get("X-Forwarded-For","")
}
self.write(result)
def make_app():
return tornado.web.Application([
(r"/ip", IndexHandler),
])
if __name__ == "__main__":
app = make_app()
app.listen(5000)
tornado.ioloop.IOLoop.current().start()
2)访问结果
和flask类似
4、补充Nginx的配置信息
server{
listen 8080;
server_name localhost;
location /api/{
rewrite ^/api/(.*)$ /$1 break;
proxy_pass http://127.0.0.1:5000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
简单的解释一下,监听8080端口,匹配以/api/开头的路由,并且重写路由,将/api/去掉,将请求给127.0.0.1:5000处理,添加四个属性到请求header
例如我请求http://www.ahutwyc.tech:8080/api/ip,那么就会被代理到http://127.0.0.1:5000/ip,当然这里127.0.0.1就是服务器内部的网络了。
四、总结
理论的东西没搞清楚,所以没法展开说,就代码实现来说是这样的,当然还有很多问题待解决,比如在代理的情况下如何获取真实ip,既然网警可以知道,那么技术上是可以实现的,是否需要原生的数据流才可以呢?或者其他非HTTP协议呢?有待探索,如果有什么问题欢迎大家讨论学习。