TypeScript 中的速率限制:工具和实现的完整指南
速率限制是保护 Web 应用程序和 API 免受滥用、DDoS 攻击和过度负载的关键技术之一。在 TypeScript 中,由于严格的类型检查和现代特性,速率限制的实现变得特别优雅和可靠。在本文中,我们将介绍 TypeScript 的最佳库、算法和代码示例。
为什么需要速率限制?
如果没有请求速率限制,您的应用程序可能会遇到:
- 服务器过载 — 单个客户端可能每秒发送数千个请求
- 暴力破解攻击 — 猜测密码或令牌
- 财务损失 — 如果每个请求都需要付费资源(例如 OpenAI API)
- 资源分配不均 — 单个用户可能占用所有带宽
TypeScript 中流行的速率限制库
1. bottleneck — 通用限制器
JavaScript/TypeScript 中最流行的速率限制库之一。支持每秒/每分钟的请求数限制,以及请求在队列中的“挂起”(累积)。
import Bottleneck from 'bottleneck';
const limiter = new Bottleneck({ maxConcurrent: 2, // 最多 2 个并发请求 minTime: 1000, // 请求之间至少间隔 1 秒 reservoir: 10, // 周期内的总限制 reservoirRefreshAmount: 10, reservoirRefreshInterval: 60 * 1000 // 每分钟刷新一次});
async function fetchData(url: string): Promise<any> { return limiter.schedule(() => fetch(url));}
// 使用const users = await Promise.all([ fetchData('/api/users/1'), fetchData('/api/users/2'), fetchData('/api/users/3'), // 此请求将等待]);2. express-rate-limit — 用于 Express.js
在 Express 应用程序中限制请求的标准解决方案。与 TypeScript 配合良好。
import express from 'express';import rateLimit from 'express-rate-limit';
const app = express();
const apiLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 分钟 max: 100, // 最多 100 个请求 standardHeaders: true, // 返回 RateLimit-* 标头 legacyHeaders: false, message: { status: 429, message: '请求过多,请稍后再试' }});
app.use('/api/', apiLimiter);
app.listen(3000);3. rate-limiter-flexible — 用于 Redis 和内置内存的灵活解决方案
支持多种存储(Redis、Memory、MongoDB、Postgres)和算法(令牌桶、滑动窗口)的库。
import { RateLimiterMemory } from 'rate-limiter-flexible';
const rateLimiter = new RateLimiterMemory({ points: 5, // 5 个请求 duration: 1, // 在 1 秒内});
async function checkRateLimit(key: string): Promise<boolean> { try { await rateLimiter.consume(key); return true; // 请求允许 } catch (error) { return false; // 超出限制 }}
// 在 Express 中的使用示例app.post('/api/login', async (req, res) => { const allowed = await checkRateLimit(req.ip); if (!allowed) { return res.status(429).json({ error: 'Too Many Requests' }); } // 处理登录...});速率限制算法
- 令牌桶 — 一个“桶”装有令牌,以恒定速率补充。每个请求消耗一个令牌。允许短暂的突发流量。
- 滑动窗口 — 一个滑动时间窗口(例如 1 分钟)。它不计算固定时间间隔内的请求,而是计算最近