Для начала опишу задачу.
У нас имеется какой-то глобальный для группы запросов роут и в нем указан посредник 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