在Heroku上使用Express.js获取客户端真实IP的方法
解决Heroku上Express获取客户端真实IP并适配express-rate-limit的问题
核心问题原因
Heroku的反向代理会屏蔽客户端真实IP,默认情况下Express拿到的是代理服务器的IP。虽然设置了trust proxy,但还需要适配Heroku的请求头规则,同时调整express-rate-limit的IP提取逻辑才能生效。
解决方案步骤
- 正确配置
trust proxy(必须放在所有中间件之前)
Heroku的代理IP段会动态变化,直接设置为true来信任所有代理节点:
const app = express(); // 这行必须放在app.use(limiter)、cors等所有中间件之前 app.set('trust proxy', true); const http = require("http"); const server = http.createServer(app); // 后续的cors、bodyParser等中间件配置...
- 修改
express-rate-limit的IP提取逻辑
Heroku会在请求头X-Forwarded-For中传递客户端真实IP(格式通常为客户端IP, 代理IP1, 代理IP2),需要手动提取第一个IP作为限流依据:
const limiter = rateLimit({ windowMs: 60 * 1000, // 1分钟 max: 15, // 每个IP每分钟最多15次请求 message: "Woah! Slow down there cowboy. You can try again in 2 minutes.", // 自定义IP提取逻辑 keyGenerator: (req) => { // 优先从X-Forwarded-For取真实IP, fallback到req.ip const clientIp = req.headers['x-forwarded-for']?.split(',')[0]?.trim() || req.ip; return clientIp; }, onLimitReached: async function(req, res, options) { try{ // 直接使用限流器生成的key(即真实客户端IP) const clientIp = options.key; console.log(`Rate limit exceeded for IP: ${clientIp}`); if(clientIp){ const geoInfo = await getGeoInfo(clientIp); // 发送Slack通知逻辑 }else{ // 无IP的通知逻辑 } }catch(err){ console.error('[E353]',err); } } });
验证方式
可以新增测试路由确认是否拿到真实IP:
app.get('/test-ip', (req) => { console.log('X-Forwarded-For:', req.headers['x-forwarded-for']); console.log('真实客户端IP:', req.ip); });
内容的提问来源于stack exchange,提问作者RandomDeveloper
相关产品推荐
相关产品推荐

