如何让express-rate-limit基于用户IP而非客户端APP IP限流?
基于真实用户IP实现API限流的解决方案
问题核心是你的API收到的请求来自React客户端应用而非用户直接请求,导致默认限流逻辑识别的是客户端应用IP而非用户真实IP。解决关键是从请求头中提取用户真实IP,同时让Express信任代理传递的头信息。
步骤1:让Express信任代理
在Express应用开头添加以下配置,确保Express能正确识别代理转发的真实IP头:
app.set('trust proxy', true);
注:DigitalOcean的部署环境(如App Platform、负载均衡)会自动将用户真实IP注入请求头,开启信任代理后Express才能正确解析这些头。
步骤2:修改限流中间件的IP提取逻辑
你可以直接从请求头中提取真实IP,或者调整request-ip的配置,以下两种方案任选其一:
方案一:直接从X-Forwarded-For头提取
X-Forwarded-For是负载均衡/反向代理常用的传递真实IP的头,修改keyGenerator:
import rateLimit from "express-rate-limit"; const apiCallRateLimiter = rateLimit({ windowMs: 60 * 60 * 1000, max: 1, message: "You have reached maximum retries. Please try again later", statusCode: 429, headers: true, keyGenerator: (req) => { // 从X-Forwarded-For头获取真实IP,格式通常是"用户IP, 代理IP1, 代理IP2..." const realIp = req.headers['x-forwarded-for']?.split(',')[0]?.trim(); // 如果取不到则回退到默认IP(比如客户端应用IP,但至少保证不会报错) return realIp || req.ip; } }); app.set('trust proxy', true); app.use(apiCallRateLimiter); app.use("/", router);
方案二:正确配置request-ip
如果坚持使用request-ip,需要指定它从代理头中提取IP,修改中间件配置:
import rateLimit from "express-rate-limit"; import { mw, getClientIp } from "request-ip"; const apiCallRateLimiter = rateLimit({ windowMs: 60 * 60 * 1000, max: 1, message: "You have reached maximum retries. Please try again later", statusCode: 429, headers: true, keyGenerator: (req) => getClientIp(req) // 使用getClientIp方法,它会自动识别代理头 }); app.set('trust proxy', true); app.use(mw({ // 配置request-ip从代理头提取IP attributeName: 'clientIp', headers: ['X-Forwarded-For', 'X-Real-IP'] })); app.use(apiCallRateLimiter); app.use("/", router);
验证方法
可以在API接口中打印相关信息,确认是否能拿到用户真实IP:
router.get('/test-ip', (req, res) => { console.log('X-Forwarded-For:', req.headers['x-forwarded-for']); console.log('req.ip:', req.ip); res.send({ realIp: req.headers['x-forwarded-for']?.split(',')[0]?.trim() || req.ip }); });
内容的提问来源于stack exchange,提问作者Fernando
相关产品推荐
相关产品推荐

