Laravel Spark - 我可以限制每月计划 API 调用和每分钟/小时 API 调用吗?

Pas*_*cut 2 php throttling laravel

我想使用 Laravel Spark 为 API 创建不同的许可证。我想限制每月以及每小时/分钟的 API 调用。例如,基本许可证允许每月 10 000 次 API 调用,但我还想限制同一帐户每小时/分钟的 API 调用。这可以用 laravel Spark 来完成吗?

有:throttle 和rate_limit,但是我可以限制每月以及每小时/分钟的API 调用总数吗?例如:每月总共 10 000 次 api 调用,每小时/分钟最多 60 次 api 调用?

根据文档,我可以限制每分钟/小时的访问:https://laravel.com/docs/6.x/routing#rate-limiting

像这样的东西结合了节流和速率限制:

Route::middleware('auth:api', 'throttle:10|rate_limit,1')->group(function () {     
Route::get('/user', function () { // }); 
});
Run Code Online (Sandbox Code Playgroud)

但我的主要问题是如何将每分钟/小时的速率限制与每月限制结合起来?

Mar*_*ean 6

来自同一文档页面:

\n
\n

您还可以将此功能与动态速率限制结合起来。例如,如果您的User模型包含一个rate_limit属性,您可以将该属性的名称传递给throttle中间件,以便使用它来计算经过身份验证的用户的最大请求计数

\n
\n\n

因此,鉴于上述情况,您可以在模型上添加一个访问器User,该访问器根据当前的订阅计划获取速率限制值:

\n
class User extends Authenticatable\n{\n    public function getRateLimitAttribute()\n    {\n        // Get license if it\'s a model\n\n        if ($license === \'basic\') {\n            return 10000;\n        }\n\n        // Return some default here\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

然后,您可以像这样使用动态速率限制值:

\n
Route::middleware(\'auth:api\', \'throttle:rate_limit,1\')->group(function () {\n    // Rate-limited routes\n});\n
Run Code Online (Sandbox Code Playgroud)\n

至于每月限制,您\xe2\x80\x99需要在某处保留一个计数器,并在每个请求时检查该计数器。您可以在另一个中间件中记录每个 API 请求:

\n
class LogRequest\n{\n    public function handle($request, Closure $next)\n    {\n        return $next($request);\n    }\n\n    public function terminate($request, $response)\n    {\n        LogRequestJob::dispatch($request);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n
class LogRequestJob implements ShouldQueue\n{\n    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;\n\n    public function __construct(Request $request)\n    {\n        $this->request = $request;\n    }\n\n    public function handle()\n    {\n        // Insert row for user to log request\n        RequestLog::create([\n            \'user_id\' => $this->request->user()->getKey(),\n            \'path\' => $this->request->path(),\n            // Store any other request data you\'re interested in\n        ]);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

然后,您\xe2\x80\x99ll需要在处理请求之前检查计数,再次使用中间件:

\n
use Symfony\\Component\\HttpKernel\\Exception\\TooManyRequestsHttpException;\n\nclass CheckRequestInLimit\n{\n    public function handle($request, Closure $next)\n    {\n        $year = Carbon::now()->year;\n        $month = Carbon::now()->month;\n        $count = RequestLog::user($request->user())->year($year)->month($month)->count();\n        $limit = $request->user()->monthly_limit; // another accessor\n\n        if ($count < $limit) {\n            return $next($request);\n        }\n\n        // Count is equal to (or greater than) limit; throw exception\n        $retryAfter = Carbon::today()->addMonth()->startOfMonth();\n        $message = \'You have exceeded your monthly limit\';\n\n        throw new TooManyRequestsHttpException($retryAfter, $message);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

希望这能给您带来思考!

\n

2021 年 11 月 1 日编辑:这个答案是针对旧版本的 Laravel 编写的。Laravel 后来引入了速率限制,这将为上述问题提供更简洁的解决方案:

\n
RateLimiter::for(\'api\', function (Request $request) {\n    return [\n        Limit::perHour(60)->by($request->user()->getKey()),\n        Limit::perDay(10000, 30)->by($request->user()->getKey()),\n    ];\n});\n
Run Code Online (Sandbox Code Playgroud)\n