Skip to content

ExpressJS - 速率限制

请求限流(Rate Limiting)是 Web 应用程序一项至关重要的安全和性能技术。它限制了用户(或 IP 地址)在给定时间段内可以发出的请求数量。这有助于防止滥用,例如:

  • 拒绝服务 (DoS) 攻击:通过过多请求使服务器过载,降低合法用户的性能。
  • 暴力破解攻击:反复尝试猜测登录或密码重置端点上的凭据。
  • 网络爬虫:阻止机器人程序从您的网站上恶意抓取内容。

express-rate-limit 中间件是 Express 中实现请求限流的行业标准。它高度可配置且易于使用。主要选项包括:

  • windowMs:检查请求的时间范围,以毫秒为单位。例如,15 * 60 * 1000 设置一个 15 分钟的窗口。
  • max(或 limit):在 windowMs 期间允许来自单个 IP 的最大连接数。一旦超出限制,后续请求将被拒绝,并返回 429 Too Many Requests 状态码。
  • message:超出限制时发送的错误消息。可以是字符串、JSON 对象或函数。
  • standardHeaders:一个布尔值(true),用于启用标准化的 RateLimit-* 响应头。
  • legacyHeaders:一个布尔值(false),用于禁用旧的、非标准的 X-RateLimit-* 头。

使用 npm 或您偏好的包管理器安装依赖。

npm install express-rate-limit

以下代码设置了一个全局请求限流器,允许每个 IP 每 15 分钟发送 100 个请求。它还展示了如何专门针对身份验证路由创建更严格的限流器。

import express from 'express';
import rateLimit from 'express-rate-limit';
const app = express();
const PORT = 3000;
// 创建一个通用请求限流器
const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 分钟
limit: 100, // 限制每个 IP 在每个“窗口”(这里是每 15 分钟)内发送 100 个请求
standardHeaders: 'draft-7', // 使用标准的 `RateLimit` 头语法
legacyHeaders: false, // 不发送 `X-RateLimit-*` 头
message: { error: 'Too many requests, please try again after 15 minutes.' },
});
// 为登录等敏感端点创建更严格的请求限流器
const loginLimiter = rateLimit({
windowMs: 10 * 60 * 1000, // 10 分钟
limit: 5, // 限制每个 IP 在每个“窗口”内尝试登录 5 次
message: { error: 'Too many login attempts, please try again after 10 minutes.' },
standardHeaders: 'draft-7',
legacyHeaders: false,
});
// 将通用限流器应用于所有对 `/api` 的请求
app.use('/api', apiLimiter);
// 一个常规的 API 路由
app.get('/api/data', (req, res) => {
res.send('This is public data.');
});
// 仅将更严格的限流器应用于登录路由
app.post('/api/login', loginLimiter, (req, res) => {
// ... 登录逻辑在此 ...
res.send('Login attempt recorded.');
});
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
  1. 运行服务器(例如,使用 npm run dev)。
  2. 在 10 分钟内向 http://localhost:3000/api/login 发送超过 5 次 POST 请求。在第 6 次请求时,您将收到一个 429 Too Many Requests 响应以及您自定义的 JSON 错误消息。
  3. 响应头将包括 RateLimit-Limit(最大请求数)、RateLimit-Remaining(剩余请求数)和 RateLimit-Reset(限流重置的时间戳)。