如何使用 Apache httpcomponents 从 NHttpRequestHandler 中告诉远程 IP 地址?

Dr.*_*ibo 3 java apache-httpcomponents

我正在使用 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
  }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,HttpComponents 4.1 中有一个额外的步骤。

Joe*_*erg 5

我花了很长时间弄清楚这一点,所以我想我会分享以防将来有人在这篇文章中徘徊。

起初,我在httpcore-nio 4.1并获得连接似乎是不可能的。最终,我用反射 hack 做到了(这可能绝不是最好的方法)。升级到 4.2.1 后就容易多了。我将在下面分享这两种解决方案。403 Forbidden如果连接的客户端不是本地主机,将返回以下代码。

HttpCore 蔚来 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;
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

HttpCore 蔚来 4.1

给智者一句话:不要这样做。它适用于 4.1,但在升级 4.2.x 时会中断。如果可以,请改为升级。

该解决方案适用于httpcore-nio 4.1但要注意,该代码是一个可怕的、可怕的反射黑客,用于从iosession最终变量 ( HttpContext) 中获取私有字段( ) 。

@Override
public void handle(final HttpRequest request, final HttpResponse response, 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);
    } 
    ...
}
Run Code Online (Sandbox Code Playgroud)