如何在Django应用中节流限制非法请求方法(GET不受限)?
Django 限制非法请求方法的请求次数方案
核心思路
- 借助Django中间件拦截请求,判断当前URL对应的允许请求方法
- 针对非法请求方法,按「用户标识+目标URL」维度统计请求次数
- 当次数超过设定阈值(如10次)时,直接返回拒绝响应
- 合法请求方法(如示例中的GET)不受任何限制,正常放行
具体实现步骤
1. 配置URL-方法允许规则
在项目的settings.py中添加配置,明确指定各URL允许的请求方法:
# settings.py ALLOWED_METHODS_PER_URL = { '/api/your-target-url/': ['GET'], # 示例URL仅允许GET请求 # 可按需添加更多URL的规则 }
2. 编写自定义中间件
在项目根目录创建middleware.py,实现次数统计与拦截逻辑:
# middleware.py from django.http import HttpResponseForbidden from django.core.cache import cache from django.conf import settings class IllegalMethodRateLimitMiddleware: def __init__(self, get_response): self.get_response = get_response self.rate_limit_threshold = 10 # 非法请求限制次数 self.cache_timeout = 3600 # 统计周期(1小时后重置次数) def __call__(self, request): current_path = request.path current_method = request.method # 检查当前URL是否有预设的允许方法规则 allowed_methods = settings.ALLOWED_METHODS_PER_URL.get(current_path) if allowed_methods and current_method not in allowed_methods: # 生成缓存键:用IP标识匿名用户,登录用户用用户ID if request.user.is_authenticated: user_identifier = request.user.id else: user_identifier = request.META.get('REMOTE_ADDR', 'unknown') cache_key = f"illegal_method_{user_identifier}_{current_path}" # 获取当前非法请求次数 current_count = cache.get(cache_key, 0) if current_count >= self.rate_limit_threshold: return HttpResponseForbidden("请求次数过多,请稍后再试") # 更新缓存中的次数 cache.set(cache_key, current_count + 1, self.cache_timeout) # 合法请求或无规则的URL,正常处理 response = self.get_response(request) return response
3. 注册中间件
在settings.py的MIDDLEWARE列表中添加自定义中间件(建议放在CsrfViewMiddleware之后):
# settings.py MIDDLEWARE = [ # ... 其他系统中间件 'django.middleware.csrf.CsrfViewMiddleware', 'your_project_name.middleware.IllegalMethodRateLimitMiddleware', # 替换为你的项目名 # ... 其他中间件 ]
4. 可选优化
- 可将阈值和缓存超时时间移至
settings.py配置,方便统一管理:
然后在中间件中引用# settings.py ILLEGAL_METHOD_RATE_LIMIT = 10 ILLEGAL_METHOD_CACHE_TIMEOUT = 3600settings.ILLEGAL_METHOD_RATE_LIMIT和settings.ILLEGAL_METHOD_CACHE_TIMEOUT - 针对API场景,可返回JSON格式的拒绝响应:
from django.http import JsonResponse return JsonResponse({"error": "请求次数过多,请稍后再试"}, status=403)
内容的提问来源于stack exchange,提问作者m tayebi
相关产品推荐
相关产品推荐

