Cloud Run服务无法获取客户端真实IP地址问题排查
问题:Cloud Run上Socket.io获取客户端IP始终显示美国地址
我在Google Cloud Run上部署了一个使用Socket.io的服务。当Socket客户端连接时,我通过如下函数从socket.handshake中提取x-forwarded-for作为客户端IP,并调用GeoPlugin接口查询地理位置。但无论用户所在位置如何,IP始终解析为美国地址。该服务已通过域名映射绑定自定义域名,且相同服务部署在Heroku时可正常获取客户端真实IP。我的Cloud Run服务均部署在us-central1区域,请问此问题的原因是什么?
函数代码:
async getSocketIP(socket) { let { headers, address } = socket.handshake; let { origin } = headers; let ip = headers['x-forwarded-for']; let userAgent = headers['user-agent']; try { let locationPointUrl = `http://www.geoplugin.net/json.gp?ip=${ip}`; let { data: location } = await axios.get(locationPointUrl); } catch (e) { console.log(`Error get client online IP on Socket IO`); } }
原因分析
- 多层转发的
x-forwarded-for头部:Cloud Run依赖全球负载均衡,当请求通过自定义域名到达服务时,x-forwarded-for头部会以逗号分隔的形式包含多个IP(格式为客户端真实IP, 负载均衡节点IP, ...)。你直接读取整个头部值,拿到的是列表中靠后的负载均衡节点IP(该节点部署在us-central1区域,所以解析为美国地址)。 - Socket.io未配置信任代理:默认情况下Socket.io不会信任代理转发的头部,无法正确识别真实的客户端IP来源。
解决方案
1. 正确解析x-forwarded-for头部
拆分逗号分隔的IP列表,取第一个值作为客户端真实IP:
async getSocketIP(socket) { let { headers } = socket.handshake; let ip = headers['x-forwarded-for']; // 提取列表中的第一个IP(客户端真实IP) if (ip) { ip = ip.split(',').shift().trim(); } let userAgent = headers['user-agent']; try { let locationPointUrl = `http://www.geoplugin.net/json.gp?ip=${ip}`; let { data: location } = await axios.get(locationPointUrl); // 处理地理位置数据 } catch (e) { console.log(`Error get client online IP on Socket IO`, e); } }
2. 配置Socket.io信任代理
在Socket.io服务端初始化时开启trustProxy选项,确保它正确处理代理转发的头部:
const io = require('socket.io')(server, { cors: { origin: "*", // 根据你的业务需求调整允许的源 methods: ["GET", "POST"] }, trustProxy: true // 关键:信任代理服务器,让Socket.io识别转发的客户端IP });
内容的提问来源于stack exchange,提问作者ololo
相关产品推荐
相关产品推荐

