skip to Main Content

i created a page visit function that works with laravel throttle. each ip/user can increase visit counter every 60 minutes.
i have a problem that can’t apply throttle on different ids and throttle works on route only 1 time per 60 minutes and does’nt care about ids:
(/home/visit/3 , /home/visit/4 ,…..): 1 time every 60 mins

route.php:

Route::post('/home/visit/{id}',[HomeController::class,'counter_visit'])->middleware('throttle:visit');

RouteServiceProvider.php

            RateLimiter::for('visit', function (Request $request) {
            return $request->user()
                ? Limit::perHour(1)->by($request->user()->id)
                : Limit::perHour(1)->by($request->ip());
                });

how can i apply throttle for each id like below?

/home/visit/3 : 1 time every 60 mins
/home/visit/4 : 1 time every 60 mins

thanks for your helps

2

Answers


  1. Chosen as BEST ANSWER

    i found the easiest way(maybe). just create a custom middleware extending ThrottleRequests.

    php artisan make:middleware ThrottleById
    

    HttpmiddlewareThrottleById.php.

    <?php
    namespace AppHttpMiddleware;
    use IlluminateRoutingMiddlewareThrottleRequests;
    class ThrottleById extends ThrottleRequests
    {
        /**
         * Handle an incoming request.
         *
         * @param  IlluminateHttpRequest  $request
         * @param  Closure(IlluminateHttpRequest): (IlluminateHttpResponse|IlluminateHttpRedirectResponse)  $next
         * @return IlluminateHttpResponse|IlluminateHttpRedirectResponse
         */
        protected function resolveRequestSignature($request)
        {
            $token = $request->route()->parameter('id'); 
            return $token;
        }
    }
    

    this function creates uique signature for each url if id parameter of route is different then just add this middleware to kernel.php same as part 3 & 4 in https://stackoverflow.com/a/75869783/9241751

    thanks to Balaji Kandasamy


  2. Currently, you are using Laravel’s built-in throttle middleware, which limits the number of requests for a given route per user or IP address, regardless of the ID parameter. To achieve throttling based on ID parameters, you need to define your own custom middleware.

    Here’s an example of how you can create a custom middleware that throttles requests based on ID:

    1. Create a new middleware class by running the following command in your terminal:

    php artisan make:middleware ThrottleById

    1. Open the newly created ThrottleById middleware class and modify the handle() method to include the following code:

      use IlluminateCacheRateLimiter;

      use SymfonyComponentHttpFoundationResponse;

      use IlluminateHttpExceptionsThrottleRequestsException;

      public function handle($request, Closure $next, $maxAttempts = 1, $decayMinutes = 60)

      {

      $limiter = app(RateLimiter::class)->for(‘visit_’.$request->route(‘id’), $maxAttempts, $decayMinutes);

      if ($limiter->tooManyAttempts($request)) {

      $retryAfter = $limiter->availableIn($request);

      throw new ThrottleRequestsException(null, $retryAfter, [

      ‘Retry-After’ => $retryAfter,

      ‘X-RateLimit-Limit’ => $maxAttempts,

      ‘X-RateLimit-Remaining’ => 0,

      ]);

      }

       $limiter->hit($request);
      
       $response = $next($request);
      
       $response->headers->add([
           'X-RateLimit-Limit' => $maxAttempts,
           'X-RateLimit-Remaining' => $limiter->retriesLeft($request),
           'X-RateLimit-Reset' => $limiter->availableAt($request),
       ]);
      
       return $response;
      

      }

    The above code is an implementation of Laravel’s built-in throttle middleware, but modified to use the ID parameter of the request to create a unique cache key for each ID.

    1. Next, register the middleware in the $routeMiddleware array in the AppHttpKernel class:

      protected $routeMiddleware = [ // ... 'throttle_by_id' => AppHttpMiddlewareThrottleById::class, ];

    2. Finally, apply the new middleware to your route definition like this:

      Route::post('/home/visit/{id}', [HomeController::class, 'counter_visit'])->middleware('throttle_by_id');

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search