更新:19.10.19
客户端ip有可能有代理,有的是自己设置的,有的是浏览器强制插入的。比如微信内置浏览器默认有代理。
通过http头的方式可以获得最前端的ip,但是http头有可能被伪造,所以建议通过Request.UserHostAddress方式获得的ip。但是使用Request.UserHostAddress有一个问题,如果客户端有代理,就会获得最后一个代理的ip,客户端可以使用代理来隐藏自己的真实ip。具体使用那种方式参考具体的应用场景。
下例优先尝试使用http头的方式获得真实ip,如果获取失败再调用Request.UserHostAddress方法。
如果有多层代理,每一层代理都有可能把自己的ip加入http头,导致最后获得的ip不止一个,例如127.0.0.1,123.123.123.123,多个ip以逗号连接。应该确保函数返回的ip长度为单个ip的长度,否则在数据库应用中有可能导致长度溢出。
下例中Log.Error函数为自己写的日志输出函数,第一个参数为错误类型,第二个参数为错误信息。可以自行删除这个函数调用。
历史版本
19.10.19.2
18.5.12.1
代码:
/// <summary>
/// 获取客户端真实IP
/// </summary>
/// <returns></returns>
public static string getRealIP()
{
try
{
string ip = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (string.IsNullOrEmpty(ip))
{
ip = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
}
if (string.IsNullOrEmpty(ip))
{
ip = HttpContext.Current.Request.UserHostAddress;
}
if (string.IsNullOrEmpty(ip))
{
Log.Error("Function.getRealIP", "ip is null or empty.");
return "0.0.0.0";
}
string[] ips = ip.Replace(" ", "").Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
string tip = ips[0];//多个ip只取第一个
if (!ipValid(tip))//验证ip格式
{
Log.Error("Function.getRealIP", "invalidIp:" + tip);
return "0.0.0.0";
}
return tip;
}
catch (Exception ex)
{
Log.Error("Function.getRealIP", ex.Message);
return "0.0.0.0";
}
}
/// <summary>
/// 验证ip格式
/// </summary>
/// <param name="ip">ip</param>
/// <returns></returns>
public static bool ipValid(string ip)
{
try
{
return Regex.IsMatch(ip, @"^((25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)$");
}
catch (Exception ex)
{
Log.Error("Function.ipValid", ex.Message);
return false;
}
}