如何使用Apache httpcomponents在NHttpRequestHandler内告诉远程IP地址?

问题描述

| 我正在使用Apache httpcomponents实现彗星风格的(延迟响应)http服务器。我的代码与http://hc.apache.org/httpcomponents-core-ga/examples.html上的“基本非阻塞HTTP服务器”示例非常相似。 就像示例代码中一样,我使用DefaultServerIOEventdispatch和DefaultListeningIOReactor调度请求。在我的NHttpRequestHandler内部,我想记录每个请求的IP地址。 在HttpRequestHandler中,您可以访问HttpRequest,HttpResponse和HttpContext。使用NHttpRequestHandler,您还将拥有一个NHttpResponseTrigger。如何获取请求来自的远程IP地址?我看不到如何使用可用的对象执行此操作。 更新,这是我最终使用的Scala代码
def getIp(context: HttpContext): Option[String] = {
  val conn = context.getAttribute(ExecutionContext.HTTP_CONNECTION)

  conn match {
    case inet: HttpInetConnection =>
      inet.getRemoteAddress match {
        case sock: java.net.InetSocketAddress => // HttpComponents 4.1
          Some(sock.getAddress.getHostAddress)
        case adr: java.net.InetAddress => // HttpComponents 4.2
          Some(adr.getHostAddress)
        case unkNown =>
          Some(unkNown.toString)
      }
    case _ => None
  }
}
如您所见,HttpComponents 4.1还有一个额外的步骤。     

解决方法

        可以将“ 1”实例转换为“ 2”类型并调用“ 3”方法以获得对端的IP。可以从作为参数传递给
HttpRequestHandler
HttpContext
实例中获得连接对象。另外,如果要将连接生命周期事件日志记录与协议处理逻辑解耦,则可能要实现“ 6”接口。 HttpCore的contrib包中还有一组日志记录类,可用于扩展具有有线和I / O事件日志记录功能的标准HttpCore类: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/httpcore-contrib/src/main/java/org/apache/http/contrib/logging/     ,        我花了一点时间来解决这个问题,所以我想我会分享的,以防将来有人徘徊于这篇文章中。 起初,我在on7ѭ上,建立联系似乎是不可能的。最终,我用反射hack做到了(这可能绝不是最好的方法)。升级到4.2.1之后,它变得相当容易。我将在下面分享这两种解决方案。如果连接的客户端不是localhost,则以下代码将返回“ 8”。 HttpCore NIO 4.2
@Override
public void handle(final HttpRequest request,final HttpResponse response,final HttpContext context) {
    HttpInetConnection connection = (HttpInetConnection) context.getAttribute(ExecutionContext.HTTP_CONNECTION);
    InetAddress ia = connection.getRemoteAddress();
    if(\"localhost\".equals(ia.getHostName()) {
        response.setStatusCode(HttpStatus.SC_FORBIDDEN);
        return;
    }
    ...
}
HttpCore NIO 4.1 明智的一句话:不要这样做。它适用于4.1,但在升级4.2.x时会中断。如果可以,请升级。 该解决方案适用于
httpcore-nio 4.1
,但是请注意,代码是一种可怕的,可怕的反思,旨在从最终变量(
HttpContext
)中获得私有字段(
iosession
)。
@Override
public void handle(final HttpRequest request,final HttpContext context) {
    try {
        Field f = context.getClass().getDeclaredField(\"iosession\");
        boolean accessible = f.isAccessible();
        Field modifiersField = Field.class.getDeclaredField(\"modifiers\");
        int modifiers = f.getModifiers();
        modifiersField.setAccessible(true);
        modifiersField.set(f,f.getModifiers() & ~Modifier.FINAL & ~Modifier.PRIVATE);
        f.setAccessible(true);
        IOSession io = (IOSession) f.get(context);
        f.setAccessible(accessible);
        modifiersField.set(f,modifiers);
        SocketAddress sa = io.getRemoteAddress();
        if(\"localhost\".equals(((InetSocketAddress) sa).getHostName())) {
            response.setStatusCode(HttpStatus.SC_FORBIDDEN);
            return;
        }
    } catch (Exception e) {
        logger.error(\"No way! I can\'t believe this fantastic piece of code threw an exception!\",e);
    } 
    ...
}