laravel 5.6 中 api 路由的 ThrottleRequestMiddleware

ThrottleRequestMiddleware for api route in laravel 5.6

我已经构建了 api 路由以将帖子作为 json 资源返回,当我将中间件 'apiThrottle:5,1' 放在 api 路由上时,它只显示结果两次然后在第三次它会生成 json 响应 'Too many attempts...'

但是当我将中间件添加到网络路由时,它会继续显示最大次数的结果(在本例中为 5 次),然后生成 'Too many attempts...'

网络路由:https://project.test/

Route::middleware('apiThrottle:5,1')->get('/', function (){
     return 'Web Route';
});

Api 路线:https://project.test/api/

Route::middleware('apiThrottle:5,1')->get('/', function (){
     return 'API Route';
});

中间件:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\JsonResponse;
use Illuminate\Routing\Middleware\ThrottleRequests;

class ThrottleRequestsMiddleware extends ThrottleRequests
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request $request
     * @param  \Closure $next
     * @param  int $maxAttempts
     * @param  int $decayMinutes
     * @return mixed
     */
    public function handle($request, Closure $next, $maxAttempts = 60, $decayMinutes = 1)
    {
        $key = $this->resolveRequestSignature($request);

        $maxAttempts = $this->resolveMaxAttempts($request, $maxAttempts);

        if ($this->limiter->tooManyAttempts($key, $maxAttempts)) {
            return $this->buildJsonResponse($key, $maxAttempts);
        }

        $this->limiter->hit($key, $decayMinutes);

        $response = $next($request);

        return $this->addHeaders(
            $response, $maxAttempts,
            $this->calculateRemainingAttempts($key, $maxAttempts)
        );
    }

    /**
     * Create a 'too many attempts' JSON response.
     *
     * @param  string  $key
     * @param  int  $maxAttempts
     * @return \Symfony\Component\HttpFoundation\Response
     */
    protected function buildJsonResponse($key, $maxAttempts)
    {
        $response = new JsonResponse([
            'error' => [
                'code' => 429,
                'message' => 'Too many attempts, please slow down the request.',
            ],
        ], 429);

        $retryAfter = $this->limiter->availableIn($key);

        return $this->addHeaders(
            $response, $maxAttempts,
            $this->calculateRemainingAttempts($key, $maxAttempts, $retryAfter),
            $retryAfter
        );
    }
}

Kernel.php:

     /**
     * The application's route middleware.
     *
     * These middleware may be assigned to groups or used individually.
     *
     * @var array
     */
    protected $routeMiddleware = [
        .
        .
        .
        'apiThrottle' => \App\Http\Middleware\ThrottleRequestsMiddleware::class,
    ];

网络路由headers:请求和响应

Content-Security-Policy: default-src 'none' ; script-src resource:; 
X-Firefox-Spdy: h2
cache-control: no-cache, private
content-type: application/json
date: Wed, 18 Apr 2018 11:57:50 GMT
retry-after: 53
server: nginx/1.13.6
set-cookie: XSRF-TOKEN=eyJpdiI6ImpRdGlIXC9KbnV3QTY2MkpKbEZUQ3d3PT0iLCJ2YWx1ZSI6IlU5YXFkZmpVXC9nMHpXSW5zK2RUZFlTVTA0N0YzaE9TeURpSHJlV0FUb1NkXC9rN3dvUUdVbzgwNHQ4MCtDU04rYjBNSHB6U2dsUzZ6cys2cGY5N1dUQVE9PSIsIm1hYyI6IjAzMTRkZTdkNmEwMzk5ODZhMTQ2ODhmYTJjOWE2ODIzODQ1YzQ0OThhY2I2NWUxOTk5MDRmNDc0ZjBjMmNjMDgifQ%3D%3D; expires=Wed, 18-Apr-2018 13:57:50 GMT; Max-Age=7200; path=/
larablog_session=eyJpdiI6IkZqaGZVUk10bFNpb2hUc2xPMXdBbVE9PSIsInZhbHVlIjoiY0hoXC9qMHFWdENIOEZZK3BaUklhMjZtQ2JoS2IwQlRTV053clUyQVd0RmpxTlRmMlVRc1Q4QW8zYUMwZSs0dmFuM3U2N3A2ZGJCZTBaN2JwdHJDSE13PT0iLCJtYWMiOiI1YzQ0ZTNjOGI4NDI3ZDg4NTI5MDQyMDRiMTc3ODk3OGZkYjk4OWJmNzhkODFkM2UwZGU1MTM0NDdmNjIxYTY1In0%3D; expires=Wed, 18-Apr-2018 13:57:50 GMT; Max-Age=7200; path=/; HttpOnly
x-ratelimit-limit: 5
x-ratelimit-remaining: 0
x-ratelimit-reset: 1524052723

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.5
Cache-Control: max-age=0
Connection: keep-alive
Cookie: XSRF-TOKEN=eyJpdiI6IkNibkJQOUM3clJscElSWGZrcDVoZGc9PSIsInZhbHVlIjoiMzJuZGljNnRzUFoxNVVOYVZscFJBRElqMHJGSGxYa2dqVXkwR0VtZlhpQUFLUkI4cHJnOFdLSGIwdEdmRnA2R2Y5WHRXZHNtTFwvUVVpc2xKM1lQVHV3PT0iLCJtYWMiOiJmNmRjMjQwMDllOWFhZGY2Y2Q2YTVmYzFjZGQxNTE4MTk3ZjRkYWUyMTA2OWY0Y2E3NGNjYTg5MmEzYTZmZjJkIn0%3D; larablog_session=eyJpdiI6IlwvUm55cHBaTVdnR21rbkJVU05DUXVBPT0iLCJ2YWx1ZSI6IkJlYVV3dXB6SUNjMkRrUHJ2bTN2R3RUa294aVpjelJlTVFCUENXVldpSzlKNWdYUTdqeHJtY1JEWXV5UUpvbUc0bHB4UG5hcGltTG9OSVYrdjBMS29BPT0iLCJtYWMiOiI0M2ZjYWMyNjY0MjFkYTlhZjZkZmQ5MjVkMDFhODZiODFiNjQ4OGIzOTViZTNmY2E2NmNhMjQzYmRiY2I4ODdhIn0%3D
Host: project.test
Referer: https://project.test/
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0

API路由headers:请求和响应

Content-Security-Policy: default-src 'none' ; script-src resource:; 
X-Firefox-Spdy: h2
cache-control: no-cache, private
content-type: application/json
date: Wed, 18 Apr 2018 11:55:55 GMT
retry-after: 57
server: nginx/1.13.6
x-ratelimit-limit: 60
x-ratelimit-remaining: 55
x-ratelimit-reset: 1524052612

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.5
Cache-Control: max-age=0
Connection: keep-alive
Cookie: XSRF-TOKEN=eyJpdiI6InFHZVFHNDg3M2hpcG9rUHd2WnlQclE9PSIsInZhbHVlIjoiQW1oZFZXbFc3NFhwVnpBTGZsM0tKbGlBaDhUNkM0TXpqMzZTb1FHUUI4bFk5XC9wWEdyK0lOZThyZ25vT2FLUHN2MXFZZGtuaVFta1lLdzBxZU9FdnR3PT0iLCJtYWMiOiJhMjM3MzA5ZDI1MmNjMjE0YTkyZjA4ODAyMzNmNDQwM2JjNTJjYzY4NzcyYWIwYWE5NjdmMWI0OTgwNjg5OGY4In0%3D; larablog_session=eyJpdiI6IjhTMnZTSmhMd3lSOUlLZzREd1BEN0E9PSIsInZhbHVlIjoiMVh2SFh4azM2RTJxRWFkV0g4YUxMUmRhVyt0bUVOYkZzbnZLRnBVb1gxQXB5OUQ2Y2lFZmNpMGt0NmNXSVlKSDFoWlE1aVZra2ROZEtYSzNpRzlVbGc9PSIsIm1hYyI6IjhmMDNmNzgzYWViODU3NzQ0MTExMzBlNWI1OTc0MTY5YzI2ZDZkZDQ2OThmZTM3NDJjZjA4MTkxN2Y0YTVhNmQifQ%3D%3D
Host: project.test
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0

请指教,

api 节流阀宣布两次,因此命中计数两次。

对于所有 api 路由,在 app/Http/Kernel 上声明了节流中间件。php

    'api' => [
        'throttle:60,1',
        'bindings',
    ],

要解决这个问题,你必须在内核文件中删除 api throttle,并且你可以在 api 路由文件中定义单独的 throttle 中间件组 app/routes/api.php如下:

// limit to 60 hits in 1 min
Route::group(['middleware' => ['throttle:60,1'], 'prefix' => 'foo'], function () {
    Route::get('/', 'FooController@fooMethod');
});

// limit to 500 hits in 1 min
Route::group(['middleware' => ['throttle:500,1'], 'prefix' => 'bar'], function () {
    Route::get('/', 'BarController@barMethod');
});

我试过了,效果很好。

php artisan cache:clear