为何Socket.IO获取IP时,socket.handshake相关语句返回两个IP地址?
为什么Socket.IO获取的IP会包含两个地址?
嘿,这个问题我之前排查类似场景时也碰到过,咱们来理清楚背后的原因和解决办法:
1. 先搞懂x-forwarded-for的本质
x-forwarded-for是一个HTTP请求头,专门用来记录客户端请求经过的代理服务器链路。它的格式是用逗号+空格分隔的IP列表:
客户端真实IP, 第一层代理IP, 第二层代理IP,...
所以当你的用户请求经过了至少一层代理(比如CDN、Nginx反向代理,甚至是用户运营商的透明代理),这个头就会包含多个IP地址。你拿到的"124.202.182.82,100.116.251.26"就是典型的x-forwarded-for值——第一个是用户的真实公网IP,第二个是请求经过的代理服务器IP。
2. 你的代码为什么会拿到这个结果?
看你的代码:
var clientIp = socket.handshake.headers['x-forwarded-for'] || socket.handshake.address var arr = clientIp.split(":"); var ip = _.last(arr);
这里有个关键错误:你用split(":")来分割字符串,但x-forwarded-for里的IP是用逗号分隔的,冒号只是用来区分IP和端口(比如192.168.1.1:8080这种场景)。
因为你拿到的x-forwarded-for值里没有冒号,所以split(":")之后数组只有一个元素,_.last(arr)就直接返回了整个x-forwarded-for字符串,这才出现了“两个IP”的情况。
3. 正确的IP获取方式
想要拿到用户的真实IP,应该这么处理:
let realIp; // 先处理x-forwarded-for的情况 if (socket.handshake.headers['x-forwarded-for']) { // 分割后去除每个IP的空格,过滤掉可能的空值 const ipList = socket.handshake.headers['x-forwarded-for'] .split(',') .map(ip => ip.trim()) .filter(ip => ip); realIp = ipList[0]; // 列表第一个就是客户端真实IP } else { // 没有代理的情况,拆分address去掉端口 const addressParts = socket.handshake.address.split(':'); realIp = addressParts[0]; }
另外要注意:得确保你的反向代理服务器(比如Nginx)正确配置了x-forwarded-for头,比如Nginx里要添加:
proxy_set_header X-Forwarded-For $remote_addr;
不然x-forwarded-for的值可能不准确或者缺失。
内容的提问来源于stack exchange,提问作者jiaguolin
相关产品推荐
相关产品推荐

