1.前言
这段时间学院要求参加去做项目并拿着做好的项目去参加比赛,我是打算做一套验证码的产品,因为考虑到一款验证码产品需要考虑到高并发的处理能力,又因为在所有Web框架里我只对python web稍微了解一点,经过权衡决定用fastapi这个框架来做,昨天晚上睡觉的时候突然想到一款验证码产品对于ip访问的限制和追踪那肯定是必不可少的,想直接在网上找现成的也没找到,于是就决定自己手搓
2.代码实现
话不多说直接上代码
from starlette.middleware.base import BaseHTTPMiddleware
from fastapi.responses import JSONResponse
from fastapi import Request, status
# 限制访问ip的中间件
class RateLimiterMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
#redis.Redis的实例,用于连接数据库
r2 = request.app.state.r2
#获取客户端的ip
client_ip = request.client.host
key = f"ip:{client_ip}"
ban_key = f"ban:{client_ip}"
limit = 100 # 限制次数
period = 300 # 时间窗口(秒)
ban_period = 300 # 封禁时间(秒)
# 检查是否在黑名单中
if await r2.get(ban_key):
resp={'msg':'Too Many Requests. You are banned for 5 minutes.'}
return JSONResponse(
content=resp, status_code=status.HTTP_403_FORBIDDEN
)
# 检查 Redis 中的访问次数
visit_count = await r2.get(key)
if visit_count is None:
# 如果没有记录,初始化访问次数
await r2.setex(key, period, 1)
else:
# 如果有记录,增加访问次数
visit_count = int(visit_count)
if visit_count >= limit:
# 如果访问次数超过限制,加入黑名单并返回 429 Too Many Requests
await r2.setex(ban_key, ban_period, 1)
# 拉入黑名单后删除记录访问次数的信息
await r2.delete(key)
resp = {'msg': 'Too Many Requests. You are banned for 5 minutes.'}
return JSONResponse(
content=resp, status_code=status.HTTP_403_FORBIDDEN
)
else:
# 否则,增加访问次数
await r2.incr(key)
# 继续处理请求
response = await call_next(request)
return response
在这个中间件中,需要导入你自己的redis实例,并且将时间窗口,限制次数,以及封禁时间给修改成你自己想要的。以我的代码举例,就是300秒内限制访问100次,若超出,则封禁300秒才能访问。中间件的作用效果是全局的,若你只想对特定的接口进行限制,可以使用装饰器
3.结语
因为本人不是软院出身的,对于开发的见解还是非常浅薄的,希望大家能多多指正