获取远程主机的 IP 地址

NET 中有一个 System.Web.HttpRequest类,它包含 ServerVariables属性,可以从 REMOTE_ADDR属性值中提供 IP 地址。

但是,我无法找到类似的方法从 ASP.NET Web API 获取远程主机的 IP 地址。

如何获取发出请求的远程主机的 IP 地址?

87217 次浏览

这是可能的,但不是很容易被发现-您需要使用来自传入请求的属性包,您需要访问的属性取决于您是使用 IIS (webhost)下的 Web API 还是自托管的。下面的代码显示了如何实现这一点。

private string GetClientIp(HttpRequestMessage request)
{
if (request.Properties.ContainsKey("MS_HttpContext"))
{
return ((HttpContextWrapper)request.Properties["MS_HttpContext"]).Request.UserHostAddress;
}


if (request.Properties.ContainsKey(RemoteEndpointMessageProperty.Name))
{
RemoteEndpointMessageProperty prop;
prop = (RemoteEndpointMessageProperty)request.Properties[RemoteEndpointMessageProperty.Name];
return prop.Address;
}


return null;
}

Carlosfigueira 提供的解决方案是可行的,但类型安全的一行程序更好: 添加一个 using System.Web,然后在您的 action 方法中访问 HttpContext.Current.Request.UserHostAddress

如果你真的想要一个一行程序并且不打算自己主持 Web API:

((System.Web.HttpContextWrapper)Request.Properties["MS_HttpContext"]).Request.UserHostAddress;

此解决方案还包括使用 Owin 自托管的 Web API。

您可以在 ApiController中创建一个私有方法,该方法将返回远程 IP 地址,无论您如何托管 Web API:

 private const string HttpContext = "MS_HttpContext";
private const string RemoteEndpointMessage =
"System.ServiceModel.Channels.RemoteEndpointMessageProperty";
private const string OwinContext = "MS_OwinContext";


private string GetClientIp(HttpRequestMessage request)
{
// Web-hosting
if (request.Properties.ContainsKey(HttpContext ))
{
HttpContextWrapper ctx =
(HttpContextWrapper)request.Properties[HttpContext];
if (ctx != null)
{
return ctx.Request.UserHostAddress;
}
}


// Self-hosting
if (request.Properties.ContainsKey(RemoteEndpointMessage))
{
RemoteEndpointMessageProperty remoteEndpoint =
(RemoteEndpointMessageProperty)request.Properties[RemoteEndpointMessage];
if (remoteEndpoint != null)
{
return remoteEndpoint.Address;
}
}


// Self-hosting using Owin
if (request.Properties.ContainsKey(OwinContext))
{
OwinContext owinContext = (OwinContext)request.Properties[OwinContext];
if (owinContext != null)
{
return owinContext.Request.RemoteIpAddress;
}
}


return null;
}

所需参考文献:

  • HttpContextWrapper-System. Web.dll
  • RemoteEndpointMessageProperty-System. ServiceModel.dll
  • OwinContext-Microsoft. Owin.dll (如果您使用 Owin 包,您将已经拥有它)

这个解决方案的一个小问题是,必须为所有3种情况加载库,而实际上在运行时只使用其中一种情况。正如建议的 给你,这可以通过使用 dynamic变量来克服。还可以编写 GetClientIpAddress方法作为 HttpRequestMethod的扩展。

using System.Net.Http;


public static class HttpRequestMessageExtensions
{
private const string HttpContext = "MS_HttpContext";
private const string RemoteEndpointMessage =
"System.ServiceModel.Channels.RemoteEndpointMessageProperty";
private const string OwinContext = "MS_OwinContext";


public static string GetClientIpAddress(this HttpRequestMessage request)
{
// Web-hosting. Needs reference to System.Web.dll
if (request.Properties.ContainsKey(HttpContext))
{
dynamic ctx = request.Properties[HttpContext];
if (ctx != null)
{
return ctx.Request.UserHostAddress;
}
}


// Self-hosting. Needs reference to System.ServiceModel.dll.
if (request.Properties.ContainsKey(RemoteEndpointMessage))
{
dynamic remoteEndpoint = request.Properties[RemoteEndpointMessage];
if (remoteEndpoint != null)
{
return remoteEndpoint.Address;
}
}


// Self-hosting using Owin. Needs reference to Microsoft.Owin.dll.
if (request.Properties.ContainsKey(OwinContext))
{
dynamic owinContext = request.Properties[OwinContext];
if (owinContext != null)
{
return owinContext.Request.RemoteIpAddress;
}
}


return null;
}
}

现在你可以这样使用它:

public class TestController : ApiController
{
[HttpPost]
[ActionName("TestRemoteIp")]
public string TestRemoteIp()
{
return Request.GetClientIpAddress();
}
}

以上答案需要参考系统。Web,以便能够将属性强制转换为 HttpContext 或 HttpContextWrapper。如果你不想要引用,你可以使用一个动态的:

var host = ((dynamic)request.Properties["MS_HttpContext"]).Request.UserHostAddress;

当服务器位于代理或负载均衡器之后时,标记的解决方案将返回代理的内部 IP 地址。在我们的示例中,我们的生产环境使用负载平衡器,而我们的开发和测试环境不使用负载平衡器,因此我修改了标记的解决方案,以便在同一代码中适应这两种情况。

public string GetSourceIp(HttpRequestMessage httpRequestMessage)
{
string result = string.Empty;


// Detect X-Forwarded-For header
if (httpRequestMessage.Headers.TryGetValues("X-Forwarded-For", out IEnumerable<string> headerValues))
{
result = headerValues.FirstOrDefault();
}
// Web-hosting
else if (httpRequestMessage.Properties.ContainsKey("MS_HttpContext"))
{
result = ((HttpContextWrapper)httpRequestMessage.Properties["MS_HttpContext"]).Request.UserHostAddress;
}
// Self-hosting
else if (httpRequestMessage.Properties.ContainsKey(RemoteEndpointMessageProperty.Name))
{
RemoteEndpointMessageProperty prop;
prop = (RemoteEndpointMessageProperty)httpRequestMessage.Properties[RemoteEndpointMessageProperty.Name];
result = prop.Address;
}


return result;
}