在负载平衡情况下使用 WCF 4.5 RemoteEndpointMessageProperty 获取客户端 IP 地址

Posted

技术标签:

【中文标题】在负载平衡情况下使用 WCF 4.5 RemoteEndpointMessageProperty 获取客户端 IP 地址【英文标题】:Get Client IP address using WCF 4.5 RemoteEndpointMessageProperty in load balancing situation 【发布时间】:2016-01-14 23:34:31 【问题描述】:

我在 IIS 中托管了 WCF 4.5 Restful 服务,我正在尝试使用 RemoteEndpointMessageProperty 获取客户端的 IP 地址 消费服务。

代码 1:

private string GetClientIP()

  OperationContext context = OperationContext.Current;
  MessageProperties prop = context.IncomingMessageProperties;
  RemoteEndpointMessageProperty endpoint =
         prop[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
  string ip = endpoint.Address;
  return ip;

代码 2:

private string GetClientIP()

  string retIp = string.Empty;
  OperationContext context = OperationContext.Current;
  MessageProperties prop = context.IncomingMessageProperties;
  HttpRequestMessageProperty endpointLoadBalancer =
  prop[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
  if (endpointLoadBalancer.Headers["X-Forwarded-For"] != null)
  
    retIp = endpointLoadBalancer.Headers["X-Forwarded-For"];
  
  if (string.IsNullOrEmpty(retIp))
  
    RemoteEndpointMessageProperty endpoint =
                prop[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
                retIp = endpoint.Address;
  
  return retIp;

但是,由于 WCF 服务托管在负载平衡器后面的 IIS 中,因此 我得到的 IP 地址始终是负载均衡器的 IP。 有什么办法可以解决这个问题,以便我可以获得真正的 IP 客户?

【问题讨论】:

通常在负载均衡器的情况下,负载均衡器使用正确的客户端 IP 地址向每个请求添加 自定义标头...验证如果是这种情况,您的托管。例如,CloudFlare 添加一个 HTTP_CF_CONNECTING_IP 标头 @balexandre,是否可以识别自定义标头? 是的,只需使用foreach 循环foreach(var s in context.Request.Headers) Log(s, context.Request.Headers[s]); ,您就会在请求中看到所有可用的标头,甚至是自定义标头。 我有类似的问题,WCF 我能够使用 TCP 绑定获取客户端 IP,但是当使用另一个绑定(Web http)时,负载平衡器 IP 被传递给服务。但我可以使用“X-Forwarded-For 标头。唯一的问题是 httpRequest 是从负载均衡器传入属性的,因此需要添加空检查 @MaheshMalpani,你能发布你的代码吗? 【参考方案1】:
OperationContext context = OperationContext.Current;
MessageProperties properties = context.IncomingMessageProperties;
RemoteEndpointMessageProperty endpoint = properties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
string address = string.Empty;
//http://www.simosh.com/article/ddbggghj-get-client-ip-address-using-wcf-4-5-remoteendpointmessageproperty-in-load-balanc.html
if (properties.Keys.Contains(HttpRequestMessageProperty.Name))

    HttpRequestMessageProperty endpointLoadBalancer = properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
    if (endpointLoadBalancer != null && endpointLoadBalancer.Headers["X-Forwarded-For"] != null)
        address = endpointLoadBalancer.Headers["X-Forwarded-For"];

if (string.IsNullOrEmpty(address))

    address = endpoint.Address;

这在负载平衡器的情况下也有效,并且在没有它的情况下也有效。我有一个端点作为 TCP,另一个端点作为 REST API 的 web http。

【讨论】:

【参考方案2】:

最重要的是如果你正在使用

async await 
OperationContext.Current; will be null

我的用法是在任何等待的调用之前获取 Ip,所以像这样使用它

var clientIpAddress = System.Web.HttpContext.Current?.Request?.UserHostAddress;

在异步服务操作中的第一个 await 语句之后,OperationContext.Current 可能为 null,因为方法体的其余部分可能在不同的线程上运行(并且 OperationContext 不会在线程之间流动

因此,您可以在任何可等待的操作之前编写代码

也许它会帮助某人:)

【讨论】:

以上是关于在负载平衡情况下使用 WCF 4.5 RemoteEndpointMessageProperty 获取客户端 IP 地址的主要内容,如果未能解决你的问题,请参考以下文章

使用 SSL 的 webHttpBinding 的 WCF 配置在负载均衡器处终止

当 Fiddler 运行 .Net 4.5 时,WCF 服务正在工作

在没有负载平衡的情况下将 docker 部署到 AWS

如何在不停机的情况下更新和 ECS 服务添加一个额外的负载平衡服务与之对话?

Jet Kafka负载平衡

负载平衡的NAT负载均衡原理