在C# MVC中获取访问网站用户的公网IP地址及地理位置
问题根因
你拿到服务器IP主要有两个核心原因:
- 站点前端存在反向代理、CDN或负载均衡节点,用户请求先经过节点转发到应用服务器,默认转发时会替换请求的
REMOTE_ADDR为节点自身IP,且你未配置节点透传客户端真实IP到请求头中,导致你读取HTTP_X_FORWARDED_FOR为空,只能拿到代理节点IP。 - 原有代码中的
GetLan分支逻辑错误,当读取到的IP是回环地址或内网IP时,会调用Dns.GetHostEntry等接口获取站点部署服务器自身的网卡IP,直接返回了服务器IP而非客户端IP。
解决方案
第一步:配置代理层透传真实IP
在你使用的反向代理/CDN/负载均衡控制台开启透传客户端真实IP配置,以Nginx为例,添加如下配置到站点规则中:
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;
第二步:修正C#获取客户端IP逻辑
丢弃原有GetLan相关的服务器IP读取逻辑,新增对X-Forwarded-ForIP链的解析处理,参考代码如下:
public static string GetRealClientIp() { var currentContext = System.Web.HttpContext.Current; if (currentContext == null) return "127.0.0.1"; string clientIp = string.Empty; // 优先解析X-Forwarded-For头,取链路第一个真实IP string xffHeader = currentContext.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; if (!string.IsNullOrWhiteSpace(xffHeader)) { string[] ipList = xffHeader.Split(',', StringSplitOptions.RemoveEmptyEntries); if (ipList.Length > 0) { clientIp = ipList.First().Trim(); } } // 兼容部分代理使用的X-Real-IP头 if (string.IsNullOrWhiteSpace(clientIp)) { clientIp = currentContext.Request.ServerVariables["HTTP_X_REAL_IP"]; } // 兜底读取REMOTE_ADDR if (string.IsNullOrWhiteSpace(clientIp)) { clientIp = currentContext.Request.ServerVariables["REMOTE_ADDR"]; } // 最后兜底读取UserHostAddress if (string.IsNullOrWhiteSpace(clientIp)) { clientIp = currentContext.Request.UserHostAddress; } // 本地回环地址处理,仅开发环境生效 if (clientIp == "::1" || clientIp == "0.0.0.0") { return "127.0.0.1"; } return clientIp; }
注意事项
X-Forwarded-For头的值为客户端真实IP,代理1IP,代理2IP格式的IP链路,直接读取整个值会包含所有代理节点IP,必须取第一个有效IP才是客户端真实IP。- 原有代码中的
GetLan分支仅适用于本地开发调试场景,生产环境必须移除,否则会触发服务器自身IP读取逻辑。 - 如果使用了第三方CDN,需确认CDN支持的真实IP请求头字段,部分CDN会使用自定义头存储真实IP,可对应添加读取逻辑。
内容的提问来源于stack exchange,提问作者Aashish Kumar
相关产品推荐
相关产品推荐

