Spec-Zone.ru › Django REST Framework

Дросселирование

HTTP/1.1 420 Улучшите свою спокойствие

Ответ на ограничение скорости API Twitter

Дросселирование, подобно разрешениям, определяет, должна ли запрос быть авторизован. Дросселирование указывает временное состояние и используется для контроля скорости запросов, которые клиенты могут отправлять в API.

Как и в случае с разрешениями, могут использоваться несколько дросселей. Ваш API может иметь ограниченный дроссель для неавторизованных запросов и менее ограниченный дроссель для авторизованных запросов.

Еще один сценарий, в котором вам может потребоваться использовать несколько дросселей, — это необходимость наложить разные ограничения на разные части API из-за того, что некоторые службы являются особенно ресурсоемкими.

Несколько дросселей также могут использоваться, если необходимо установить как скорости дросселирования burst, так и скорости дросселирования sustained. Например, вы можете ограничить пользователя максимум 60 запросами в минуту и 1000 запросами в день.

Дроссели не обязательно относятся только к ограничению скорости запросов. Например, служба хранения может также нуждаться в дросселировании по пропускной способности, а платная служба данных может ограничить доступ к определенному количеству записей.

**Дросселирование на уровне приложения, предоставляемое REST framework, не следует рассматривать как средство защиты или защиту от brute forcing или атак типа denial-of-service. Злонамеренные пользователи всегда смогут подделывать IP-адреса источника. Кроме того, встроенные реализации дросселирования реализованы с использованием фреймворка кэширования Django и используют неатомарные операции для определения скорости запросов, что иногда может привести к некоторой неопределенности.**

Дросселирование на уровне приложения, предоставляемое REST framework, предназначено для реализации политик, таких как различные бизнес-уровни и базовая защита от чрезмерного использования сервиса.

Как определяется дросселирование

Как и в случае с разрешениями и аутентификацией, дросселирование в REST framework всегда определяется как список классов.

Перед выполнением основной части представления каждый дроссель в списке проверяется. Если проверка любого дросселя завершается неудачей, будет поднято исключение exceptions.Throttled, и основная часть представления не будет выполнена.

Настройка политики дросселирования

Политика дросселирования по умолчанию может быть настроена глобально с помощью настроек DEFAULT_THROTTLE_CLASSES и DEFAULT_THROTTLE_RATES. Например.

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ],
    'DEFAULT_THROTTLE_RATES': {
        'anon': '100/day',
        'user': '1000/day'
    }
}

Описание скоростей, используемых в DEFAULT_THROTTLE_RATES, может включать second, minute, hour или day в качестве периода дросселирования.

Вы также можете настроить политику дросселирования на уровне представления или набора представлений, используя классовые представления APIView.

from rest_framework.response import Response
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView

class ExampleView(APIView):
    throttle_classes = [UserRateThrottle]

    def get(self, request, format=None):
        content = {
            'status': 'request was permitted'
        }
        return Response(content)

Если вы используете декоратор @api_view с представлениями на основе функций, вы можете использовать следующий декоратор.

@api_view(['GET'])
@throttle_classes([UserRateThrottle])
def example_view(request, format=None):
    content = {
        'status': 'request was permitted'
    }
    return Response(content)

Также возможно настроить классы дросселирования для маршрутов, созданных с помощью декоратора @action. Классы дросселирования, установленные таким образом, переопределят любые настройки классов на уровне набора представлений.

@action(detail=True, methods=["post"], throttle_classes=[UserRateThrottle])
def example_adhoc_method(request, pk=None):
    content = {
        'status': 'request was permitted'
    }
    return Response(content)

Как идентифицируются клиенты

Заголовок X-Forwarded-For HTTP и переменная REMOTE_ADDR WSGI используются для уникальной идентификации IP-адресов клиентов для дросселирования. Если заголовок X-Forwarded-For присутствует, он будет использован; в противном случае будет использовано значение переменной REMOTE_ADDR из среды WSGI.

Если вам необходимо строго идентифицировать уникальные IP-адреса клиентов, вам необходимо сначала настроить количество прикладных прокси, за которыми работает API, установив настройку NUM_PROXIES. Это значение должно быть целым числом от нуля и выше. Если оно установлено не в ноль, то IP-адрес клиента будет определяться как последний IP-адрес в заголовке X-Forwarded-For, после исключения IP-адресов всех прикладных прокси. Если значение установлено в ноль, то значение REMOTE_ADDR всегда будет использоваться в качестве идентифицируемого IP-адреса.

Важно понимать, что если вы настроите настройку NUM_PROXIES, все клиенты за уникальным шлюзом NAT будут рассматриваться как один клиент.

Дополнительные сведения о работе заголовка X-Forwarded-For и идентификации удаленного IP-адреса можно найти здесь.

Настройка кэша

Классы дросселирования, предоставляемые REST framework, используют кеш-бекенд Django. Вы должны убедиться, что вы установили соответствующие настройки кэша. Значение по умолчанию для бекенда LocMemCache должно подойти для простых конфигураций. Более подробную информацию см. в документации Django по кэшированию.

Если вам необходимо использовать кэш, отличный от 'default', вы можете сделать это, создав пользовательский класс дросселирования и установив атрибут cache. Например:

from django.core.cache import caches

class CustomAnonRateThrottle(AnonRateThrottle):
    cache = caches['alternate']

Необходимо также запомнить установку вашего пользовательского класса дросселирования в настройке 'DEFAULT_THROTTLE_CLASSES' или с помощью атрибута представления throttle_classes.

Примечание по конкурентности

Встроенные реализации дросселирования уязвимы для гонок, поэтому при высокой конкурентности они могут пропускать несколько дополнительных запросов.

Если ваш проект требует гарантии количества запросов во время одновременных запросов, вам необходимо реализовать собственный класс дросселирования. Дополнительную информацию см. в вопросе #5181.

Справочник API

AnonRateThrottle

AnonRateThrottle будет ограничивать только неавторизованных пользователей. IP-адрес входящего запроса используется для создания уникального ключа для дросселирования.

Скорость разрешенных запросов определяется одним из следующих (в порядке предпочтения):

  • Свойство rate класса, которое можно задать путем переопределения AnonRateThrottle и установки свойства.
  • Настройка DEFAULT_THROTTLE_RATES['anon'].

AnonRateThrottle подходит, если вы хотите ограничить скорость запросов от неизвестных источников.

UserRateThrottle

UserRateThrottle будет ограничивать пользователей до заданной скорости запросов по всему API. Идентификатор пользователя используется для создания уникального ключа для дросселирования. Неавторизованные запросы будут возвращаться к использованию IP-адреса входящего запроса для создания уникального ключа для дросселирования.

Скорость разрешенных запросов определяется одним из следующих (в порядке предпочтения):

  • Свойство rate класса, которое можно задать путем переопределения UserRateThrottle и установки свойства.
  • Настройка DEFAULT_THROTTLE_RATES['user'].

В API может быть несколько UserRateThrottles одновременно. Для этого переопределите UserRateThrottle и задайте уникальный «scope» для каждого класса.

Например, несколько скоростей дросселирования пользователей можно реализовать, используя следующие классы...

class BurstRateThrottle(UserRateThrottle):
    scope = 'burst'

class SustainedRateThrottle(UserRateThrottle):
    scope = 'sustained'

...и следующие настройки.

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': [
        'example.throttles.BurstRateThrottle',
        'example.throttles.SustainedRateThrottle'
    ],
    'DEFAULT_THROTTLE_RATES': {
        'burst': '60/min',
        'sustained': '1000/day'
    }
}

UserRateThrottle подходит, если вы хотите реализовать простые глобальные ограничения скорости на пользователя.

ScopedRateThrottle

Класс ScopedRateThrottle может использоваться для ограничения доступа к определенным частям API. Этот дроссель будет применяться только если представление, к которому осуществляется доступ, включает свойство .throttle_scope. Уникальный ключ дросселирования затем будет сформирован путем конкатенации «scope» запроса с уникальным идентификатором пользователя или IP-адресом.

Разрешенная скорость запросов определяется настройкой DEFAULT_THROTTLE_RATES с использованием ключа из «scope» запроса.

Например, при следующих представлениях...

class ContactListView(APIView):
    throttle_scope = 'contacts'
    ...

class ContactDetailView(APIView):
    throttle_scope = 'contacts'
    ...

class UploadView(APIView):
    throttle_scope = 'uploads'
    ...

...и следующих настройках.

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.ScopedRateThrottle',
    ],
    'DEFAULT_THROTTLE_RATES': {
        'contacts': '1000/day',
        'uploads': '20/day'
    }
}

Запросы пользователей к ContactListView или ContactDetailView будут ограничены до 1000 запросов в день. Запросы пользователей к UploadView будут ограничены до 20 запросов в день.

Пользовательские дроссели

Чтобы создать пользовательский дроссель, переопределите BaseThrottle и реализуйте .allow_request(self, request, view). Метод должен возвращать True если запрос должен быть разрешен и False в противном случае.

Необязательно, вы также можете переопределить метод .wait(). Если он реализован, .wait() должен возвращать рекомендуемое количество секунд ожидания перед следующей попыткой запроса или None. Метод .wait() будет вызван только в том случае, если .allow_request() ранее возвращал False.

Если метод .wait() реализован и запрос заблокирован, заголовок Retry-After будет включен в ответ.

Пример

Следующий пример дросселирования скорости, которое случайным образом заблокирует 1 из каждых 10 запросов.

import random

class RandomRateThrottle(throttling.BaseThrottle):
    def allow_request(self, request, view):
        return random.randint(1, 10) != 1

throttling.py

Copyright © 2011–present Encode OSS Ltd.
Licensed under the BSD License.
https://www.django-rest-framework.org/api-guide/throttling/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API