Регулирование вложенных запросов к роутам в Laravel

Для начала опишу задачу.

У нас имеется какой-то глобальный для группы запросов роут и в нем указан посредник throttle. Затем мы пытаемся добавить еще один throttle на внутренний для этой группы роут.

// User can send 1000 requests of any kind in an hour.
Route::prefix('image')->middleware('auth', 'throttle:1000,60')->group(function() {
    // User can download 10 times a minute.
    Route::post('/download', 'ImageController@download')->middleware('throttle:10,1');
    // User can search 100 times an hour
    Route::get('/search', 'ImageController@search')->middleware('throttle:100,60');
    // Use default throttle, user can send 1000 images in an hour.
    Route::get('/send', 'ImageController@send');
});

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

Я столкнулся с этой проблемой. И после некоторого раздумья я понял, что это действительно верное поведение – ведь посредник throttle на одном хите вызывается теперь дважды, и заголовок X-RateLimit-Remaining теперь уменьшается на два, а не на один. Но как нам преодолеть эту проблему?

  • Мы можем удалить глобальный посредник throttle и просто применить его на всех маршрутах, которые нам нужны. (Правда из-за этого будет довольно много повторений)
  • Возможно, мы можем переопределить посредника по умолчанию и реализовать какой-то идентификатор, который мы будем использовать для их различия.

К счастью, у Laravel уже есть решение для нас! К сожалению, в документации об этом ничего не говорится, однако все довольно просто – третьим параметром мы должны указать префикс нашего посредника.

// User can send 1000 requests of any kind in an hour.
Route::prefix('image')->middleware('auth', 'throttle:1000,60')->group(function() {
    // User can download 10 times a minute.
    Route::post('/download', 'ImageController@download')->middleware('throttle:10,1,minute_download');
    // User can search 100 times an hour
    Route::get('/search', 'ImageController@search')->middleware('throttle:100,60,search');
    // Use default throttle, user can send 1000 images in an hour.
    Route::get('/send', 'ImageController@send');
});

Вышеприведенная группа маршрутов включает в себя три маршрута внутри посредников auth и throttle. Эти два посредника можно рассматривать как глобальные для маршрутов внутри этой группы. В зависимости от сценария мы могли бы рассмотреть возможность применения различных значений throttle для некоторых маршрутов в группе. Это относится к маршрутам /download и /search – мы хотим иметь для них более низкий лимит запросов (в текущем случае). Мы достигаем этого, передавая третий аргумент посреднику. Это значение префикса, которое будет использоваться для их отличия – throttle:max_requests,period,prefix.

Эта функция была введена в Laravel 6.0. Для всех предыдущих версий, вам нужно переопределить Throttle по умолчанию и реализовать свое собственное решение.

https://ntsanov.com/blog/nested-request-throttling-in-laravel

Рейтинг
( 3 оценки, среднее 5 из 5 )
Максим Гречушников/ автор статьи
Мне 40 лет, и больше половины жизни я занимаюсь разработкой. За это время я работал с корпоративными системами, highload-проектами, интеграциями, платежными решениями, внутренними платформами и legacy-кодом, который пережил не одного разработчика. Некоторые системы, кажется, переживут и нас. Моя специализация — PHP, Laravel, backend-архитектура, DDD, тестирование, рефакторинг и техническое лидерство. Мне интересны задачи, где нужно соединить код, бизнес, данные, процессы и здравый смысл. Последние годы я много работаю с LLM и AI-инструментами: использую их для проектирования, анализа кода, документации, тестов, ревью, работы с legacy и построения инженерных процессов. Для меня LLM — это не замена разработчику, а усилитель для тех, кто умеет думать системно. В блоге я пишу о Laravel, PHP, архитектуре, тестировании, инженерной практике, управлении разработкой и реальном применении AI в работе программиста.
Понравилась статья? Поделиться с друзьями: