عند العمل على Laravel RESTful API، واحدة من الإمور التي يجب معرفتها والإهتمام بها هي Rate Limit، فما هي.
هي ألية يوفرها إطار العمل لارافيل، من أجل تحديد عدد الطلبات للروابط، حيث تساعد في:
وبهذه الطريقة تبقى دائما واجهة API الخاصه بنا، متاحة للمستخدمين الحقيقيين.
للتوضيح أكثر
لفرض أن لدينا هذا الرابط http://www.test.test/api/v2/brands وتتم زيارته (طلبه)، ألاف المرات في نفس الثانية من قبل نفس المستخدم، فإذا كانت موارد السيرفر لا تتحمل ذلك فإن الموقع لن يستجيب له مما يعني تعطيل الموقع عن جميع المستخدمين.
فيمكن تعريف Rate Limiting بأنها تقنية يمكن من خلالها التحكم في إستهلاك الموارد من خلال تحديد عدد الطلبات لكل مستخدم.
وفر إطار العمل لارافيل middleware إفتراضي باسم throttle حيث يمكننا من:
حماية التطبيق بشكل كامل
للقيام بذلك يمكننا الذهاب إلى app/http/kernel.php وتعديل middlewaregroups->api من
'api' => [ 'throttle:api', \Illuminate\Routing\Middleware\SubstituteBindings::class, ],
إلى
'api' => [ 'throttle:60,1', \Illuminate\Routing\Middleware\SubstituteBindings::class, ],
كما نلاحظ أنه تم تعديل throttle بـ throttle:2,1 لكن ماذا تعني throttle:2,1 ؟ تعني أنه يسمح بأن يتم الطلب مرتين في كل ثانية، فلو كانت throttle:10,1 فذلك يعني أنه يسمح بالطلب 10 مرات في كل ثانية.
في حال أنه تم طلب الرابط للمرة الثالثة فإننا سوف نحصل على الخطأ التالي
429 | TOO MANY REQUESTS
حماية routes معينة.
إذا كنا لا نريد تطبيق Rate Limiting على جميع التطبيق، وأن يتم تطبيقة على routes معينة، بالإمكان إنشاء group في ملف api.php أو routes.php
Route::group(['middleware'=>'throttle:2,1'],function (){ Route::apiResource('brands',BrandController::class); });
لو ذهبنا للملف RouteServiceProvider نجد الدالة configureRateLimiting ، نجد بها rate limiter باسم api
protected function configureRateLimiting() { RateLimiter::for('api', function (Request $request) { return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip()); }); }
حيث تسمح هذه الدالة بـ 60 طلب بالدقيقة وذلك بالإعتماد على user->id إذا كان مسجل دخول أو request->ip إذا لم يكن المستخدم مسجل دخول.
ولإستخدام هذه الدالة، يجب تطبيقها على routes
Route::middleware(['throttle:api'])->group(function () { Route::apiResource('brands', BrandController::class); });
مثال أخر على تطبيق rate limiting بحيث يسمح بمائة طلب للمستخدمين المسجلين، ومائة طلب بإستخدام ip للـ guests.
هنا سأقوم بإنشاء middleware جديد بإسم uploads في داخل الدالة configureRateLimiting في الملف RouteServiceProvider
protected function configureRateLimiting() { RateLimiter::for('api', function (Request $request) { return Limit::perMinute(2)->by(optional($request->user())->id ?: $request->ip()); }); RateLimiter::for('uploads', function (Request $request) { return $request->user() ? Limit::perMinute(100)->by($request->user()->id) : Limit::perMinute(10)->by($request->ip()); }); }
ولتطبيق uploads middleware الذي قمنا بإنشاؤه
Route::middleware(['throttle:uploads'])->group(function () { Route::apiResource('brands', BrandController::class); });
كما نلاحظ أنه يمكن تطبيق Rate Limiting على الروابط، فورم تسجيل الدخول، فورم إدخال البيانات، رفع الملفات .... وذلك من خلال middleware=>throttling.
كما نعلم أنه في حال زيادة عدد الطلبات عن الحد المسموح به فإنه سيتم إرجاع الخطأ 429 | TOO MANY REQUESTS ، لكن ماذا لو أردنا إرجاع رسالة خطأ مخصصة.
إنشاء throttle باسم global
protected function configureRateLimiting()
{
RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(2)->by(optional($request->user())->id ?: $request->ip());
});
RateLimiter::for('global', function (Request $request) {
return Limit::perMinute(2)->response(function () {
return response('Custom response...', 429);
});
});
}
تطبيق هذا throttle على route
Route::middleware(['throttle:global'])->group(function () { Route::apiResource('brands', BrandController::class); });
هنا الأن في حالة زيادة عدد الطلبات عن 2 سيتم إرجاع الرسالة Custome response مع status code = 429
Nane
awesome!