You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:55:21