Django Ratelimit 提供了一个装饰器来限制视图。限制可以基于 IP 地址或请求中的字段。本文主要介绍Python Django中,配置使用django-ratelimit限制网站接口访问频率的方法,以及相关的示例代码。

1、使用pip安装django-ratelimit

pip install django-ratelimit

2、配置使用django-ratelimit

Django Ratelimit是 Django 视图的速率限制装饰器,将速率数据存储在配置好的Django Cache中,确保使用的Cache设置为持久化的,并且可以跨多个部署worker实例工作(例如UWSGI worker)。

相关文档:https://docs.djangoproject.com/en/dev/topics/cache/

在视图views.py中使用装饰器,如下,

from ratelimit.decorators import ratelimit

@ratelimit(key='ip', rate='5/m')
def myview(request):
    # Will be true if the same IP makes more than 5 POST
    # requests/minute.
    was_limited = getattr(request, 'limited', False)
    return HttpResponse()

@ratelimit(key='ip', rate='5/m', block=True)
def myview(request):
    # If the same IP makes >5 reqs/min, will raise Ratelimited
    return HttpResponse()

@ratelimit(key='post:username', rate='5/m', method=['GET', 'POST'])
def login(request):
    # If the same username is used >5 times/min, this will be True.
    # The `username` value will come from GET or POST, determined by the
    # request method.
    was_limited = getattr(request, 'limited', False)
    return HttpResponse()

@ratelimit(key='post:username', rate='5/m')
@ratelimit(key='post:tenant', rate='5/m')
def login(request):
    # Use multiple keys by stacking decorators.
    return HttpResponse()

@ratelimit(key='get:q', rate='5/m')
@ratelimit(key='post:q', rate='5/m')
def search(request):
    # These two decorators combine to form one rate limit: the same search
    # query can only be tried 5 times a minute, regardless of the request
    # method (GET or POST)
    return HttpResponse()

@ratelimit(key='ip', rate='4/h')
def slow(request):
    # Allow 4 reqs/hour.
    return HttpResponse()

rate = lambda g, r: None if r.user.is_authenticated else '100/h'
@ratelimit(key='ip', rate=rate)
def skipif1(request):
    # Only rate limit anonymous requests
    return HttpResponse()

@ratelimit(key='user_or_ip', rate='10/s')
@ratelimit(key='user_or_ip', rate='100/m')
def burst_limit(request):
    # Implement a separate burst limit.
    return HttpResponse()

@ratelimit(group='expensive', key='user_or_ip', rate='10/h')
def expensive_view_a(request):
    return something_expensive()

@ratelimit(group='expensive', key='user_or_ip', rate='10/h')
def expensive_view_b(request):
    # Shares a counter with expensive_view_a
    return something_else_expensive()

@ratelimit(key='header:x-cluster-client-ip')
def post(request):
    # Uses the X-Cluster-Client-IP header value.
    return HttpResponse()

@ratelimit(key=lambda g, r: r.META.get('HTTP_X_CLUSTER_CLIENT_IP',
                                       r.META['REMOTE_ADDR'])
def myview(request):
    # Use `X-Cluster-Client-IP` but fall back to REMOTE_ADDR.
    return HttpResponse()

3、配置说明

@ratelimit(group=None, key=, rate=None, method=ALL, block=False)

参数

描述

group

一组要一起计算的速率限制。默认为视图的全名(fn.qualname),

具体逻辑可以查看一下源码。

key

装饰器的key=参数采用字符串或可调用对象。

可选值如下:

1)'ip' 是使用请求IP地址(request.META['REMOTE_ADDR'])

2)'get:X'request.GET.get('X', '')的值

3)'post:X'request.POST.get('X', '')的值

4)'header:x-x'request.META.get('HTTP_X_X', '')的值

(右边的值将被转换为全大写,

任何破折号都将替换为下划线,例如:x-client-ip => X_CLIENT_IP。)

5)'user'request.user的值,不要与未经身份验证的用户一起使用。

6)'user_or_ip' 如果用户通过身份验证,则使用适当的值request.user

否则使用 request.META['REMOTE_ADDR']

注意:缺少的header、GET 和 POST 值都将被视为空字符串,

并在同一个存储中进行速率限制。

相关文档:https://django-ratelimit.readthedocs.io/en/stable/keys.html#keys-chapter

rate

'5/m' 每单位时间允许的请求数。单位是:s是秒,m是分钟,h是小时,

d是天。也接受可调用对象。它们应该返回一个简单的速率字符串,

或者一个整数元组。例如:(count, seconds)

0/s不允许所有请求的速率。None表示“无限制”,将允许所有请求。

相关文档https://django-ratelimit.readthedocs.io/en/stable/rates.html#rates-chapter

method

所有要限制速率的HTTP方法。可以是字符串,字符串的列表/元组,

或者是ALLUNSAFE(包括POST, PUT, DELETEPATCH)的特殊值。

block

是否阻止请求,blockTrue,才会执行raise Ratelimited(),限制才会生效

要将@ratelimit装饰器与基于类的视图一起使用,需要使用 Django@method_decorator,如下,

from django.utils.decorators import method_decorator
from django.views.generic import View

class MyView(View):
    @method_decorator(ratelimit(key='ip', rate='1/m', method='GET'))
    def get(self, request):
        pass

@method_decorator(ratelimit(key='ip', rate='1/m', method='GET'), name='get')
class MyOtherView(View):
    def get(self, request):
        pass

每个装饰器可以限制为一个或多个 HTTP 方法。该 method=参数接受方法名称(例如'GET')或字符串列表或元组(例如('GET', 'OPTIONS'))

有两个特殊的快捷键值,都可以从ratelimit装饰器或is_ratelimited helper中访问,也可以在ratelimit模块中访问,如下,

from ratelimit.decorators import ratelimit

@ratelimit(key='ip', method=ratelimit.ALL)
@ratelimit(key='ip', method=ratelimit.UNSAFE)
def myview(request):
    pass

参考文档https://django-ratelimit.readthedocs.io/en/stable/

推荐文档