> For the complete documentation index, see [llms.txt](https://ilyachch.gitbook.io/django-rest-framework-russian-documentation/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ilyachch.gitbook.io/django-rest-framework-russian-documentation/overview/navigaciya-po-api/throttling.md).

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

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

> HTTP/1.1 420 Повышение спокойствия
>
> [Twitter API ограничение скорости ответа](https://developer.twitter.com/en/docs/basics/rate-limiting)

Дросселирование аналогично [permissions](/django-rest-framework-russian-documentation/overview/navigaciya-po-api/permissions.md), поскольку оно определяет, должен ли запрос быть авторизован. Дроссели обозначают временное состояние и используются для контроля скорости запросов, которые клиенты могут делать к API.

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

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

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

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

\*\*Дросселирование на уровне приложения, которое обеспечивает DRF, не следует рассматривать как меру безопасности или защиту от перебора или атак типа "отказ в обслуживании". Намеренно злоумышленники всегда смогут подделать IP-адреса. В дополнение к этому, встроенная реализация дросселирования реализована с использованием кэш-фреймворка Django и использует неатомарные операции для определения скорости запросов, что иногда может привести к некоторой нечеткости.

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

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

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

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

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

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

```python
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`.

```python
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` с представлениями, основанными на функциях, вы можете использовать следующий декоратор.

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

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

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

### Как определяются клиенты

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

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

Важно понимать, что если вы настроите параметр `NUM_PROXIES`, то все клиенты за уникальным [NAT-ом](https://en.wikipedia.org/wiki/Network_address_translation) шлюзом будут рассматриваться как один клиент.

Дополнительную информацию о том, как работает заголовок `X-Forwarded-For` и как определить IP удаленного клиента, можно найти [здесь](http://oxpedia.org/wiki/index.php?title=AppSuite:Grizzly#Multiple_Proxies_in_front_of_the_cluster).

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

Классы дросселирования, предоставляемые DRF, используют бэкенд кэша Django. Вы должны убедиться, что установили соответствующие настройки [cache settings](https://docs.djangoproject.com/en/stable/ref/settings/#caches). Значение по умолчанию бэкенда `LocMemCache` должно быть приемлемым для простых настроек. Более подробную информацию можно найти в [документации по кэшу](https://docs.djangoproject.com/en/stable/topics/cache/#setting-up-the-cache) Django.

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

```python
from django.core.cache import caches

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

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

### Заметка о параллелизме

Встроенные реализации дросселей открыты для [условий гонки](https://en.wikipedia.org/wiki/Race_condition#Data_race), поэтому при высоком параллелизме они могут пропустить несколько лишних запросов.

Если ваш проект полагается на гарантию количества запросов во время одновременных запросов, вам необходимо реализовать свой собственный класс дросселя. Более подробную информацию смотрите в [issue #5181](https://github.com/encode/django-rest-framework/issues/5181).

***

## API Reference

### AnonRateThrottle

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

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

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

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

### UserRateThrottle

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

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

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

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

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

```python
class BurstRateThrottle(UserRateThrottle):
    scope = 'burst'

class SustainedRateThrottle(UserRateThrottle):
    scope = 'sustained'
```

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

```python
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'` запроса.

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

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

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

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

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

```python
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 запросов.

```python
import random

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