Nuxt + EO + Nginx 透传获取用户真实IP
在基于 Nuxt 开发个人博客项目时,我遇到了一个核心痛点:生产环境通过路由代理转发请求后,后端服务始终无法获取用户真实 IP,要么固定显示服务器出口 IP,要么 IP 随机跳动,直接导致博客阅览量统计失真、当日点赞防刷机制完全失效。
经过逐层排查,问题根源集中在Nuxt 路由代理配置、EdgeOne (EO) CDN 透传规则、Nginx 反向代理、后端 IP 获取逻辑四个环节的链路断裂。本文将完整复盘问题场景、根因分析与最终解决方案,帮助大家规避同类代理环境下的 IP 透传坑点。
一、问题场景复现:两种错误配置引发的 IP 异常
我的新项目采用Nuxt3作为前端框架,通过routeRules配置路由代理转发/api/、/emoji/请求,后端使用 Java 服务,接入腾讯云 EdgeOne (EO) CDN 加速,前端请求经过「用户→EO→Nginx→Nuxt 代理→后端服务」的全链路,IP 获取异常分两个阶段:
阶段 1:代理指向远程服务,IP 固定为服务器出口 IP
最初的 Nuxt 配置直接将请求代理到远程正式服务:
// nuxt.config.ts 错误配置1
routeRules: {
'/api/**': { proxy: 'https://www.dreamcenter.top/api/**' },
'/emoji/**': { proxy: 'https://www.dreamcenter.top/emoji/**' }
}问题表现:后端通过request.getHeader("X-Real-IP")获取的 IP永远固定为 101.43.71.114(服务器出口 IP),所有用户的请求都被识别为同一个 IP,阅览量统计、防刷逻辑完全失效。
根因:请求直接代理到远程域名,经过 EO CDN 和服务器多层转发后,Nuxt 代理没有透传用户真实 IP,后端只能收到最上层代理的服务器 IP。
阶段 2:代理指向本地服务,IP 随机跳动
为了解决远程代理问题,我修改配置区分开发 / 生产环境,生产环境将请求代理到本地后端服务:
// nuxt.config.ts 优化配置
routeRules: {
'/api/**': {
proxy: process.env.NODE_ENV === 'development'
? 'https://www.dreamcenter.top/api/**' // 开发环境代理远程
: 'http://127.0.0.1:9999/api/**' // 生产环境代理本地后端
},
'/emoji/**': {
proxy: process.env.NODE_ENV === 'development'
? 'https://www.dreamcenter.top/emoji/**'
: 'http://127.0.0.1:9999/emoji/**'
}
}问题表现:IP 不再固定,但每次请求的 IP 都随机变化,后端依然无法识别真实用户。
根因:请求经过 EdgeOne CDN 转发后,IP 被多层代理封装,单纯依赖X-Real-IP只能获取到代理层 IP,而非用户真实 IP。
二、核心原理:多层代理下的 IP 透传规则
在EO CDN → Nginx → Nuxt → 后端服务的多层代理架构中,用户真实 IP 会被层层覆盖,必须通过标准请求头透传:
- EdgeOne 会将用户真实 IP 放在
EO-Real-IP请求头中; - Nginx 需要接收 EO 的真实 IP,并追加到
X-Forwarded-For、X-Real-IP; - Nuxt 本地代理不篡改请求头,直接转发 Nginx 传递的 IP 头;
- 后端不能只依赖单个请求头,必须兼容多层代理的标准头格式。
三、全链路解决方案:从 Nginx 到后端的 IP 透传配置
1. Nginx 配置:开启 EO 真实 IP 透传
Nginx 只需配置标准代理请求头转发规则,即可将 EdgeOne 传递的用户真实 IP 透传给 Nuxt。经实测,无需启用 set_real_ip_from、real_ip_header 等针对 EO 的专用配置,相关配置项暂时注释,后续可根据运行情况观察是否需要为 EO 单独配置 EO-Real-IP。
Nginx 会将包含用户真实 IP 的信息封装到标准请求头中转发给 Nuxt,其中 X-Forwarded-For 是多层代理环境下获取用户真实 IP 最关键的请求头,能够完整记录代理链路中的所有 IP 信息,保障后端可以正确解析。
server {
listen 443 ssl;
server_name dreamcenter.top;
# 核心:开启EdgeOne真实IP透传 (实测配不配置貌似都不影响,先注释,后续待观察验证是否需要给EO单独配置一个EO-Real-IP)
# set_real_ip_from 101.43.71.114; # 信任EO出口IP
# real_ip_header EO-Real-IP; # 从EO自定义头获取真实IP
# real_ip_recursive on; # 递归获取最上层真实IP
# SSL配置(原有配置保留)
ssl_certificate C:\data\ssl/dreamcenter.top_nginx/dreamcenter.top_bundle.crt;
ssl_certificate_key C:\data\ssl/dreamcenter.top_nginx/dreamcenter.top.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
# 静态资源配置(原有配置保留)
location = /baidu_verify_codeva-vmodcnnE0h.html {
alias C:/data/dreamcenter/stable/baidu_verify_codeva-vmodcnnE0h.html;
}
location /ads.txt {
alias C:/data/dreamcenter/stable/ads.txt;
}
location /stable/ {
alias C:/data/dreamcenter/stable/;
}
# 转发Nuxt服务,标准传递IP请求头
location / {
proxy_pass http://127.0.0.1:33330; # 转发Nuxt服务
# 核心:透传真实IP请求头
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr; # 单层代理IP
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 多层代理IP链
}
}关键作用:Nginx 会将 EO 传递的真实 IP,替换为标准的 X-Forwarded-For 和 X-Real-IP 请求头,转发给 Nuxt。(实际最有作用的是 X-Forwarded-For)
2. Nuxt 配置:本地代理不篡改请求头
保持上文区分环境的代理配置即可:生产环境直接代理本地后端服务,Nuxt 会自动透传 Nginx 传递的 IP 请求头,无需额外配置。
3. 后端工具类:兼容多层代理的真实 IP 获取
后端放弃单一X-Real-IP获取方式,编写通用工具类,优先读取标准多层代理头X-Forwarded-For,兼容所有代理场景:
package top.dreamcenter.dreamcenter.utils;
import javax.servlet.http.HttpServletRequest;
public class CommonUtil {
/**
* 获取用户真实IP,兼容多层代理、CDN、Nginx场景
*/
public static String getClientIp(HttpServletRequest request) {
// 1. 优先从X-Forwarded-For获取(标准多层代理头,格式:用户IP,代理1,代理2...)
String ip = request.getHeader("X-Forwarded-For");
if (ip != null && !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip)) {
// 取第一个非unknown的IP,即用户真实IP
return ip.split(",")[0].trim();
}
// 2. 其次读取X-Real-IP(Nginx直接传递的IP)
ip = request.getHeader("X-Real-IP");
if (ip != null && !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip)) {
return ip;
}
// 3. 兜底:直接获取连接IP(无代理时生效)
ip = request.getRemoteAddr();
// 4. 最终兜底:返回匿名标识
return (ip == null || ip.isEmpty()) ? "anonymous" : ip;
}
}四、最终效果
完成以上三层配置后,项目完美解决了 IP 获取问题:
- 阅览量统计精准:每个用户的真实 IP 被正确识别,访问记录不再重复 / 失真;
- 点赞防刷生效:基于真实 IP 限制当日点赞次数,杜绝恶意刷赞;
- 全链路兼容:开发环境代理远程、生产环境代理本地,均能正常获取 IP。
五、总结:多层代理 IP 透传核心要点
- CDN 层:确认服务商的真实 IP 请求头(如 EO 的
EO-Real-IP),配置信任 IP(暂且貌似不用额外配置); - 代理层(Nginx):必须开启
real_ip规则,透传标准 IP 请求头; - 应用层(Nuxt):本地代理优先转发本地服务,避免远程代理丢失 IP;
- 后端层:绝不依赖单一 IP 头,必须兼容
X-Forwarded-For多层代理标准。
这套方案适用于所有 Nuxt+CDN+Nginx 的前后端分离项目,彻底解决代理环境下的真实 IP 获取难题。
总结
- 多层代理下 IP 获取失败的核心是请求头未透传,而非单一配置问题;
- Nginx 的
real_ip配置是衔接 CDN 与应用的关键,必须信任 CDN IP; - 后端通用 IP 工具类是最终保障,优先读取
X-Forwarded-For标准头; - Nuxt 生产环境建议代理本地服务,最大化保留请求头原始信息。
💬 评论区 (1)
发表评论