Node.js(Express)获取移动端真实IP及设备IP限流实现问题
问题解答
一、为什么获取的IP是本地回环地址或IPv6地址?
1. 本地回环地址:1(即::1)的原因
这种情况多发生在本地开发场景:你的React Native真机通过Expo Go访问本地后端时,请求大概率经过了Expo的本地代理转发,后端实际收到的请求来自代理服务器的本地回环地址,而非手机的真实IP。另外,如果你的Express服务器仅监听localhost/127.0.0.1(未监听0.0.0.0),也会导致请求被代理转发后显示回环地址。
2. 拿到IPv6地址的原因
现在多数设备和网络默认优先支持IPv6协议,当你的手机和后端处于IPv6网络环境(比如局域网开启了IPv6),请求会通过IPv6链路传输,此时获取到的IPv6地址就是设备的真实IP,并非无效地址。
二、如何实现基于设备IP的用户限流?
第一步:确保正确获取设备真实IP
- 本地开发场景:先配置Express信任代理,在代码开头添加
app.set('trust proxy', 'loopback'),让req.ip能正确解析经过Expo代理后的客户端IP;同时确保Express服务器监听0.0.0.0(而非localhost),比如启动命令用app.listen(3000, '0.0.0.0')。 - 生产环境(有Nginx/Cloudflare等反向代理):同样需要设置
app.set('trust proxy', true)(或指定代理IP范围),这样req.ip和req.headers['x-forwarded-for']才能拿到真实的客户端IP。
第二步:使用限流中间件实现IP限流
推荐用express-rate-limit这个轻量的Express限流库,步骤如下:
- 安装依赖:
npm install express-rate-limit
- 在Express中配置限流规则:
const rateLimit = require('express-rate-limit'); // 配置限流规则 const ipLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 时间窗口:15分钟 max: 100, // 每个IP在窗口内最多允许100次请求 // 自定义IP获取逻辑,优先取代理传递的真实IP keyGenerator: (req) => { // 从x-forwarded-for中取第一个IP(避免多级代理的情况),没有则用req.ip或连接地址 const clientIp = req.headers['x-forwarded-for']?.split(',')[0].trim() || req.ip || req.connection.remoteAddress; return clientIp; }, handler: (req, res) => { res.status(429).json({ message: '请求过于频繁,请15分钟后再试' }); } }); // 应用到所有API路由 app.use('/api', ipLimiter);
注意事项
- IPv6地址可以直接作为限流的标识,
express-rate-limit完全支持IPv6格式的IP作为key。 - 移动网络下,设备的公网IP其实是基站(路由器)的IP,同基站下的设备会共享这个IP,这种场景下无法通过IP区分单个设备,若需要更精准的限流,可结合客户端生成的唯一设备UUID(存在本地存储,每次请求携带),但这已经超出纯IP限流的范畴。
内容的提问来源于stack exchange,提问作者learncode
相关产品推荐
相关产品推荐

