简体   繁体   中英

Rate Limit for only success requests (Laravel 9)

Is there anyway to apply rate limiting to the route but for only success responses. Like for example if user sends request to send/code endpoint 5 times and if all of them was successful then block the user to send request again. But if 2 of them was unsuccessful (like validation error or something) but 3 was successful then user should have 2 more attempts for the given time.

I know rate limiting checks before request get executed, then block or let the user to continue. But is there anyway to apply my logic or should I try to approach differently?

You would probably need to make your own middleware, but you can extend the ThrottleRequests class and just customize how you want to handle responses:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Routing\Middleware\ThrottleRequests;
use Illuminate\Support\Arr;

class ThrottleSuccess extends ThrottleRequests
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  array  $limits
     * @return \Symfony\Component\HttpFoundation\Response
     *
     * @throws \Illuminate\Http\Exceptions\ThrottleRequestsException
     */
    protected function handleRequest($request, Closure $next, array $limits)
    {
        $response = $next($request); // call the controller first

        if ($response->statusCode === 200) { // only hit limiter on successful response
            foreach ($limits as $limit) {
                if ($this->limiter->tooManyAttempts($limit->key, $limit->maxAttempts)) {
                    throw $this->buildException($request, $limit->key, $limit->maxAttempts, $limit->responseCallback);
                }
    
                $this->limiter->hit($limit->key, $limit->decayMinutes * 60);
            }
        }

        foreach ($limits as $limit) {
            $response = $this->addHeaders(
                $response,
                $limit->maxAttempts,
                $this->calculateRemainingAttempts($limit->key, $limit->maxAttempts)
            );
        }

        return $response;
    }
}

Then add your middleware to Kernel.php :

    protected $routeMiddleware = [
        // ...
        'throttle.success' => ThrottleSuccess::class,
        // ...
    ];

Then use it in a route like the original throttle middleware:

Route::middleware('throttle.success:5,1')->group(function () {
    // ...
});

Note: you may have to override handleRequestUsingNamedLimiter if you want to return a custom response built from RateLimiter::for , I have not done anything for that here.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM