express-rate-limit为何对客户端发起的服务器请求不生效?
express-rate-limit 对客户端接口请求不生效的问题排查
我用React和JavaScript搭建了一个前后端分离的Web应用,在服务端的app.js里配置了express-rate-limit限流中间件:
require("./DB/connectToDb"); // require("./primeryData/primeryCards")(); const express = require("express"); const app = express(); const rateLimit = require("express-rate-limit"); const usersRouter = require("./Routes/Users/userRouter"); const cardsRouter = require("./Routes/Cards/cardsRouter"); const ordersRouter = require("./Routes/Orders/OrderRouter"); const chalk = require("chalk"); const morgan = require("morgan"); const cors = require("cors"); app.use(morgan(chalk.cyan(":method :url :status :response-time ms"))); app.use(cors()); app.use(express.json()); app.use("/api/users", usersRouter); app.use("/api/cards", cardsRouter); app.use("/api/orders", ordersRouter); const PORT = 8181; app.listen(PORT, () => console.log(chalk.blueBright.bold(`server run on: http://:localhost:${PORT}`)) ); const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 10, // Limit each IP to 100 requests per `window` (here, per 15 minutes) message: "Limited I Guess..." }) app.get("/",limiter,(req,res)=>res.send(req.ip)); app.use('/api', limiter);
直接在浏览器访问http://localhost:8181/时,页面会显示我的IP(::1),刷新10次以上会触发限流提示"Limited I Guess...",符合预期。但通过客户端调用服务端的API接口时,却能无限制发起请求。想知道是不是漏了什么配置?express-rate-limit对客户端发起的请求到底有没有效?
以下是服务端API示例:
/********** Like/Dislike Card **********/ router.patch("/card-like/:id", auth, async (req, res) => { try { // console.log(req.params.id); const user = req.user; let card = await Card.findOne({ _id: req.params.id }); const cardLikes = card.likes.find((id) => id === user._id); if (!cardLikes) { card.likes.push(user._id); card = await card.save(); return res.send(card); } const cardFiltered = card.likes.filter((id) => id !== user._id); card.likes = cardFiltered; card = await card.save(); return res.send(card); } catch (error) { console.log(chalk.redBright("Could not edit like:", error.message)); return res.status(500).send(error.message); } });
问题原因
核心问题是中间件挂载顺序错误:
- 你先挂载了
/api/users、/api/cards、/api/orders这些路由,之后才挂载app.use('/api', limiter)限流中间件。 - Express的中间件和路由是按注册顺序匹配执行的,当请求命中前面的
/api/*路由时,会直接进入对应路由处理逻辑并返回响应,后续的限流中间件根本不会被执行。
解决方法
调整代码顺序,把限流中间件的挂载移到所有/api前缀的路由之前:
require("./DB/connectToDb"); // require("./primeryData/primeryCards")(); const express = require("express"); const app = express(); const rateLimit = require("express-rate-limit"); const usersRouter = require("./Routes/Users/userRouter"); const cardsRouter = require("./Routes/Cards/cardsRouter"); const ordersRouter = require("./Routes/Orders/OrderRouter"); const chalk = require("chalk"); const morgan = require("morgan"); const cors = require("cors"); app.use(morgan(chalk.cyan(":method :url :status :response-time ms"))); app.use(cors()); app.use(express.json()); // 先注册/api前缀的限流中间件 const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15分钟 max: 10, // 每个IP在15分钟内最多10次请求 message: "Limited I Guess..." }); app.use('/api', limiter); // 再注册各个/api路由 app.use("/api/users", usersRouter); app.use("/api/cards", cardsRouter); app.use("/api/orders", ordersRouter); const PORT = 8181; // 建议把app.listen放在所有配置最后,结构更清晰 app.listen(PORT, () => console.log(chalk.blueBright.bold(`server run on: http://localhost:${PORT}`)) ); app.get("/", limiter, (req, res) => res.send(req.ip));
补充说明
express-rate-limit对客户端发起的请求完全生效,只要中间件能被正确执行到。- 另外注意原代码中
app.listen放在了中间件和路由注册之前,虽然不影响功能,但将其移到所有配置最后,代码结构会更清晰易维护。
内容的提问来源于stack exchange,提问作者Anonymous Op
相关产品推荐
相关产品推荐

