在开发 Web 应用程序时,经常需要对请求进行限制,以保护应用程序免受恶意请求的影响。下面介绍如何使用 Express 框架编写 IP 请求频率限制中间件,以限制每个 IP 地址的请求频率。
介绍
使用 Express 框架来创建一个简单的应用程序,并实施一个中间件来限制每个 IP 地址的请求频率。定义一个最大请求数量(maxLimitPerIP
)和一个时间周期(oneDayTs
)来限制每个 IP 地址在给定时间内可以发起的请求数量。
实现步骤
以下是实现 IP 请求频率限制中间件的步骤:
步骤 1:设置应用程序和中间件
导入 Express 模块并设置应用程序的基本配置。定义一个监听端口(port
)来启动服务器,并创建一个 Express 应用程序实例。
const express = require('express');
const app = express();
const port = 3000;
const maxLimitPerIP = 10;
const oneDayTs = 1000 * 60 * 60 * 24;
监听端口为 3000,并设置了每个 IP 地址的最大请求数量为 10,时间周期为 24 小时。
步骤 2:编写日志记录中间件
为了调试和监控,编写一个简单的日志记录中间件函数 middlewareLogger
,记录每个请求的方法、URL 和时间戳。
const middlewareLogger = (req, res, next) => {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
next();
}
app.use(middlewareLogger);
这个中间件函数在每个请求到达时执行,并在控制台打印请求的详细信息。
步骤 3:实现 IP 请求频率限制中间件
定义了一个变量 lastTs
来存储上一次重置请求计数器的时间戳和一个对象 requestCounts
来存储每个 IP 地址的请求计数器。
let lastTs = 0;
let requestCounts = {};
接下来,编写一个中间件函数 rateLimiter
来实施 IP 请求频率限制。中间件函数将在每个请求到达时执行,并根据 IP 地址和请求计数器判断是否超过了限制。
const rateLimiter = (req, res, next) => {
const now = Date.now();
if (now - lastTs > oneDayTs) {
lastTs = now;//now - (now % (1000 * 60 * 60 * 24))
requestCounts = {};
}
const clientIP = req.ip;
if (requestCounts[clientIP]) {
requestCounts[clientIP]++;
} else {
requestCounts[clientIP] = 1;
}
if (requestCounts[clientIP] > maxLimitPerIP) {
return res.status(429).send({ message: "Too many requests!" });
}
next();
};
app.get('/info', rateLimiter, function (req, res, next) {
res.json({ message: "hello world" });
})
检查是否超过了时间周期(这里设为 24 小时),如果超出了,重置请求计数器 requestCounts
为一个空对象,并更新 lastTs
为当前时间戳。
获取请求的 IP 地址,并检查该 IP 地址的请求计数器。如果计数器存在,则递增计数器;否则将计数器初始化为 1。
检查该 IP 地址的计数器是否超过了设定的最大请求数量 maxLimitPerIP
。如果超过了阈值,返回一个 HTTP状态码 429(过多请求)给客户端,并发送一个包含错误消息的 JSON 响应。
步骤 4:定义路由和启动应用程序
定义一些简单的路由处理程序并将中间件 rateLimiter
应用到需要进行请求频率限制的路由上。
app.get('/user', function (req, res, next) {
res.json({ name: "tom", age: 24 });
})
app.get('/info', rateLimiter, function (req, res, next) {
res.json({ message: "hello world" });
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
定义了两个路由处理程序。其中 /user
路由不受请求频率限制,而 /info
路由将应用中间件 rateLimiter
来限制 IP 地址的请求频率。
使用 app.listen
方法启动应用程序并监听指定的端口。