如何为Wagtail的InfoPage页面设置访问速率限制?
在Wagtail中为InfoPage设置访问速率限制的方案
方法1:直接给Page模型的serve方法添加ratelimit装饰器
这种方式最直接,仅针对单个页面模型生效。只需在你的InfoPage类中重写serve方法并加上原有的@ratelimit装饰器:
from ratelimit.decorators import ratelimit from wagtail.models import Page from django.db import models from wagtail.fields import RichTextField from wagtail.admin.panels import FieldPanel class InfoPage(Page): template = "wagtail/info_page.html" last_modified_date = models.DateField("Last modified date") body = RichTextField(features=['bold', 'italic', 'link', 'ul', 'h3']) content_panels = Page.content_panels + [ FieldPanel('last_modified_date'), FieldPanel('body') ] parent_page_types = ['news.Index'] subpage_types = [] @ratelimit(key='ip', rate='15/m', block=True) def serve(self, request, *args, **kwargs): return super().serve(request, *args, **kwargs)
装饰器会直接作用于页面的请求处理逻辑,达到和原Django视图完全一致的限制效果。
方法2:使用自定义中间件批量限制
如果需要给多个页面类型统一添加速率限制,中间件是更高效的选择。创建一个自定义中间件,自动检查请求对应的页面类型并应用限制:
- 在项目目录下创建
middleware.py文件,写入以下代码:
from ratelimit.core import is_ratelimited from ratelimit.exceptions import Ratelimited from django.http import HttpResponseForbidden from wagtail.models import Page from .models import InfoPage class InfoPageRateLimitMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): try: # 获取当前请求对应的具体页面实例 page = Page.objects.get(url_path=request.path).specific if isinstance(page, InfoPage): # 检查并应用速率限制 ratelimited = is_ratelimited( request=request, key='ip', rate='15/m', increment=True, ) if ratelimited: raise Ratelimited() except Page.DoesNotExist: # 非Wagtail页面请求,直接跳过 pass response = self.get_response(request) return response def process_exception(self, request, exception): # 捕获速率限制异常,返回403响应 if isinstance(exception, Ratelimited): return HttpResponseForbidden("请求过于频繁,请稍后再试")
- 在
settings.py的MIDDLEWARE列表中添加这个中间件:
MIDDLEWARE = [ # 其他已存在的中间件... 'your_project_name.middleware.InfoPageRateLimitMiddleware', ]
方法3:利用Wagtail的before_serve_page钩子
Wagtail提供了页面渲染前的钩子,可以在不修改模型或中间件的前提下,插入速率限制逻辑:
在项目的wagtail_hooks.py文件中添加以下代码:
from wagtail.core import hooks from ratelimit.core import is_ratelimited from django.http import HttpResponseForbidden from .models import InfoPage @hooks.register('before_serve_page') def rate_limit_info_pages(page, request, serve_args, serve_kwargs): # 仅对InfoPage类型的页面应用限制 if isinstance(page, InfoPage): ratelimited = is_ratelimited( request=request, key='ip', rate='15/m', increment=True, ) if ratelimited: return HttpResponseForbidden("请求过于频繁,请稍后再试") # 返回None表示继续执行原有渲染逻辑 return None
通用注意事项
确保你原有的Redis缓存配置仍然生效,django-ratelimit需要依赖缓存存储限制记录,在settings.py中确认:
CACHES = { 'default': { 'BACKEND': 'django_redis.cache.RedisCache', 'LOCATION': 'redis://127.0.0.1:6379/1', 'OPTIONS': { 'CLIENT_CLASS': 'django_redis.client.DefaultClient', } } } # 指定ratelimit使用的缓存后端 RATELIMIT_STORAGE = 'django_ratelimit.backends.cache.CacheBackend'
内容的提问来源于stack exchange,提问作者redtomato
相关产品推荐
相关产品推荐

