TypeScript 底层原理:轻松实现速率限制与节流

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

如何防止您的 API 在请求洪流中崩溃

\n\n

想象一下:您启动了一个很棒的服務,用 TypeScript 编写了后端,然后——砰!——一个“好心”的用户运行了一个脚本,每秒向您的端点发送数千个请求。服务器崩溃,数据库不堪重负,而诚实的用户只能看到 502 错误。熟悉吗?

\n\n

在 Web 开发世界中,rate limiting(速率限制) 和 throttling(节流) 不仅仅是时髦的词汇,更是您 API 的救生圈。今天,我们将探讨如何在不伤脑筋的情况下,用 TypeScript 实现这些机制。开始吧!

\n\n

Rate limiting vs Throttling:有什么区别?

\n\n

在编写代码之前,让我们先明确区分这两个概念。很多人会混淆它们,但区别是根本性的。

\n\n
    \n
  • Rate limiting — 是一种硬性限制:“来自同一个 IP 的请求每分钟不超过 100 个”。超出限制?您将收到 429 Too Many Requests 错误,并在窗口期结束前被阻止。它在 API 网关层面工作。
  • \n
  • Throttling — 是一种平滑调节:“您可以发送请求,但每秒不超过一个”。其他请求要么排队,要么被忽略,但用户不会被阻止。
  • \n
\n\n

一个简单的类比:rate limiting 就像地铁的闸机(刷卡通过,否则等待),而 throttling 就像路口的交通指挥员(车辆通行,但有间隔)。

\n\n

何时需要?真实场景

\n\n

您可能会说:“我的网站很小,为什么需要这个?”原因如下:

\n\n
    \n
  • 防御 DDoS 和暴力破解 — 攻击者无法暴力破解密码或使服务器瘫痪。
  • \n
  • 节省资源 — 付费 API(例如 OpenAI)每次调用都会收费。限制客户端可以节省预算。
  • \n
  • 公平分配负载 — 一个“吵闹”的用户不会压垮所有其他用户。
  • \n
  • 遵守 SLA — 如果您承诺 99.9% 的正常运行时间,没有限制是不行的。
  • \n
\n\n

用 TypeScript 编写 Rate Limiting:简单入门

\n\n

我们从基础示例开始——基于固定窗口(Fixed Window)的 in-memory rate limiter。它将请求计数器直接存储在应用程序内存中。

\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 {\                

博客

书籍推荐