获取远程主机的IP地址
Posted
技术标签:
【中文标题】获取远程主机的IP地址【英文标题】:Get the IP address of the remote host 【发布时间】:2012-03-22 21:07:22 【问题描述】:在 ASP.NET 中有一个System.Web.HttpRequest
类,其中包含ServerVariables
属性,它可以从REMOTE_ADDR
属性值中为我们提供IP 地址。
但是,我找不到类似的方法来从 ASP.NET Web API 获取远程主机的 IP 地址。
如何获取发出请求的远程主机的 IP 地址?
【问题讨论】:
我找到的最简单的方法在这里:***.com/questions/53211824/… 【参考方案1】:可以这样做,但不是很容易发现 - 您需要使用传入请求中的属性包,而您需要访问的属性取决于您是使用 IIS(webhosted)下的 Web API 还是 self -托管。下面的代码展示了如何做到这一点。
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;
【讨论】:
谢谢,我也在找这个。小改进 = 扩展类:gist.github.com/2653453 WebAPI 大部分都非常干净。很遗憾,像 IP 这样的微不足道的东西需要这样的代码。RemoteEndpointMessageProperty
是System.ServiceModel.Channels
命名空间System.ServiceModel.dll
程序集中的类吗?那不是属于 WCF 的程序集吗?
@Slauma,是的,他们是。 ASP.NET Web API(当前)以两种“风格”实现,自托管和网络托管。 Web 托管版本是在 ASP.NET 之上实现的,而自托管版本是在 WCF 侦听器之上实现的。请注意,平台(ASP.NET Web API)本身与主机无关,因此将来有人可能会实现不同的主机,主机将以不同的方式显示该属性(远程端点)。
不幸的是,如果您使用 Owin 自托管,这将不起作用(推荐用于 Web API 2)。如果有的话需要另一个...【参考方案2】:
此解决方案还涵盖使用 Owin 自托管的 Web API。部分来自here。
您可以在 ApiController
中创建一个私有方法,无论您如何托管您的 Web API,它都会返回远程 IP 地址:
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 种情况加载库,而在运行时您实际上只使用其中一种。正如here 建议的那样,这可以通过使用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();
【讨论】:
这个解决方案应该使用这个命名空间“System.Net.Http”来工作。由于这是 Assembly System.Web.Http.dll 上的类名,v5.2.2.0。 @WagnerBertolini,你是对的,你需要using System.Net.Http;
行,因为你正在扩展HttpRequestMessage
。除非您在 System.Net.Http
命名空间中定义您的扩展,否则这是非常值得怀疑的。但不确定它是否必不可少,因为它会被任何 IDE 或生产力工具自动添加。你怎么看?
我急于在这里完成一项工作,我花了 20 多分钟才看到构建错误发生了什么。我只是复制了代码并为它创建了一个类,在编译时它没有显示方法,当我在 VS 上使用“转到定义”时,它把我带到了我的班级,我一直不明白发生了什么,直到我找到了另一个班级。扩展是一个相当新的功能,并不是一直都在使用,因为,我认为节省这段时间是个好主意。
使用 OWIN 时,您可以使用 OwinHttpRequestMessageExtensions 来获取 OWIN 上下文,例如:request.GetOwinContext().Request.RemoteIpAddress
其实应该是 var ctx = request.Properties[MsHttpContext] as HttpContextWrapper; E如果你转换,你不需要检查 null 因为如果转换失败,你会得到一个异常【参考方案3】:
如果您真的想要一个单行且不打算自托管 Web API:
((System.Web.HttpContextWrapper)Request.Properties["MS_HttpContext"]).Request.UserHostAddress;
【讨论】:
【参考方案4】:以上答案需要引用 System.Web 才能将属性转换为 HttpContext 或 HttpContextWrapper。如果您不想要引用,您可以使用动态获取 ip:
var host = ((dynamic)request.Properties["MS_HttpContext"]).Request.UserHostAddress;
【讨论】:
【参考方案5】:当服务器位于代理或负载平衡器后面时,标记的解决方案将返回代理的内部 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;
【讨论】:
正是我想要的。大多数值得生产的应用程序都在重写标头的代理后面,这是处理该问题的方法..【参考方案6】:carlosfigueira 提供的解决方案有效,但类型安全的单行更好:添加 using System.Web
然后在您的操作方法中访问 HttpContext.Current.Request.UserHostAddress
。
【讨论】:
-1 这不能在 web api 中被信任,因为HttpContext.Current
没有在整个任务管道中正确持久化;因为所有请求处理都是异步的。 HttpContext.Current
在编写 Web API 代码时几乎总是应该避免的。
@Andras,我想更详细地了解为什么使用 HttpContext.Current 不好,你知道任何有价值的资源吗?
嗨@CuongLe;事实上 - 虽然线程问题可能是一个问题(尽管如果SynchronizationContext
在任务之间正确流动,则并不总是直接的);最大的问题是您的服务代码是否可能是自托管的(例如测试)-HttpContext.Current
是一个纯粹的 Asp.Net 构造,并且在您自托管时不存在。
类型安全并不是一切。如果从线程(例如任务等待器,在现代 Web API 代码中非常常见)或自托管上下文中使用,此代码将引发难以调试的 NullReferenceException
。至少大多数其他答案只会返回null
。以上是关于获取远程主机的IP地址的主要内容,如果未能解决你的问题,请参考以下文章