TypeScript تحت الغطاء: تحديد المعدل والتحكم في التدفق دون ألم

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

كيف لا تدع API الخاص بك ينهار تحت وابل من الطلبات

\n\n

تخيل: لقد أطلقت خدمة رائعة، وكتبت الواجهة الخلفية (Backend) باستخدام TypeScript، وفجأة! مستخدم "لطيف" يبدأ تشغيل سكريبت يقصف نقطة النهاية (Endpoint) الخاصة بك بآلاف الطلبات في الثانية. الخادم ينهار، قاعدة البيانات تغرق، والمستخدمون الشرفاء يرون خطأ 502. هل هذا مألوف؟

\n\n

في عالم تطوير الويب، تحديد المعدل (Rate Limiting) والتحكم في التدفق (Throttling) ليسا مجرد كلمات رنانة، بل هما طوق نجاة لـ API الخاص بك. اليوم سنشرح كيفية تنفيذ هذه الآليات في TypeScript دون تعقيد. هيا بنا!

\n\n

تحديد المعدل (Rate Limiting) مقابل التحكم في التدفق (Throttling): ما الفرق؟

\n\n

قبل كتابة الكود، دعنا نفصل بين المفهومين بوضوح. كثيرون يخلطون بينهما، لكن الفرق جوهري.

\n\n
    \n
  • تحديد المعدل (Rate Limiting) — هو حد صارم: "لا يزيد عن 100 طلب في الدقيقة من نفس IP". تجاوزته؟ تحصل على 429 Too Many Requests وحظر حتى نهاية النافذة. يعمل على مستوى بوابة API.
  • \n
  • التحكم في التدفق (Throttling) — هو تنظيم سلس: "يمكنك إرسال الطلبات، ولكن ليس أكثر من مرة واحدة في الثانية". يتم إما وضع الطلبات المتبقية في قائمة انتظار أو تجاهلها، لكن المستخدم لا يتم حظره.
  • \n
\n\n

تشبيه بسيط: تحديد المعدل (Rate Limiting) يشبه البوابة الدوارة في المترو (مررت البطاقة - دخلت، لا - قف)، بينما التحكم في التدفق (Throttling) يشبه شرطي المرور عند التقاطع (السيارات تسير ولكن بفاصل زمني).

\n\n

متى تحتاج هذا؟ سيناريوهات حقيقية

\n\n

قد تقول: "موقعي صغير، لماذا أحتاج هذا؟" إليك الأسباب:

\n\n
    \n
  • الحماية من هجمات DDoS والتخمين العنيف (Brute Force) — لن يتمكن المهاجمون من تخمين كلمات المرور أو إسقاط الخادم.
  • \n
  • توفير الموارد — خدمات API المدفوعة (مثل OpenAI) تفرض رسوماً على كل استدعاء. بتحديد العملاء، ستنقذ ميزانيتك.
  • \n
  • توزيع الحمل العادل — مستخدم واحد "مزعج" لن يضغط على جميع المستخدمين الآخرين.
  • \n
  • الامتثال لاتفاقية مستوى الخدمة (SLA) — إذا كنت تعد بوقت تشغيل (Uptime) بنسبة 99.9%، فلا غنى عن التحديدات.
  • \n
\n\n

نكتب تحديد المعدل (Rate Limiting) في TypeScript: بداية بسيطة

\n\n

لنبدأ بمثال أساسي — محدد معدل في الذاكرة (In-Memory Rate Limiter) يعتمد على النافذة الثابتة (Fixed Window). يخزن عدادات الطلبات مباشرة في ذاكرة التطبيق.

\n\n
// rateLimiter.ts\nimport { Request, Response, NextFunction } from 'express';\n\ninterface RateLimitEntry {\n    count: number;\n    resetTime: number;\n}\n\nclass InMemoryRateLimiter {\n    private store: Map<string, RateLimitEntry> = new Map();\n    private windowMs: number;\n    private maxRequests: number;\n\n    constructor(windowMs: number, maxRequests: number) {\n        this.windowMs = windowMs;\n        this.maxRequests = maxRequests;\n    }\n\n    public middleware() {\n        return (req: Request, res: Response, next: NextFunction): void => {\n            const key = req.ip || 'unknown';\n            const now = Date.now();\n            let entry = this.store.get(key);\n\n            if (!entry || now > entry.resetTime) {\n                // نافذة جديدة\n                entry = { count: 0, resetTime: now + this.windowMs };\n                this.store.set(key, entry);\n            }\n\n            entry.count++;\n\n            if (entry.count > this.maxRequests) {\n                res.status(429).json({\n                    error: 'Too Many Requests',\n                    retryAfter: Math.ceil((entry.resetTime - now) / 1000)\n                });\n                return;\n            }\n\n            // تمرير معلومات الحد في الترويسات\n            res.setHeader('X-RateLimit-Limit', this.maxRequests);\n            res.setHeader('X-RateLimit-Remaining', this.maxRequests - entry.count);\n            res.setHeader('X-RateLimit-Reset', Math.ceil(entry.resetTime / 1000));\n\n            next();\n        };\n    }\n\n    // تنظيف السجلات القديمة (لمنع تسرب الذاكرة)\n    public cleanup(): void {\                

المدونات

توصيات الكتب