3

Apache httpcomponents を使用して、コメット スタイル (遅延応答) の http サーバーを実装しています。私のコードは、 http://hc.apache.org/httpcomponents-core-ga/examples.htmlの「基本的なノンブロッキング HTTP サーバー」の例と非常によく似ています。

コード例と同様に、DefaultServerIOEventDispatch と DefaultListeningIOReactor を使用してリクエストをディスパッチします。NHttpRequestHandler 内で、各リクエストの IP アドレスをログに記録したいと思います。

HttpRequestHandler 内では、HttpRequest、HttpResponse、および HttpContext にアクセスできます。NHttpRequestHandler には、NHttpResponseTrigger もあります。リクエストの送信元のリモート IP アドレスを取得するにはどうすればよいですか? 利用可能なオブジェクトでこれを行う方法がわかりません。

Update、これが私が最終的に使用した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 には追加の手順があります。

4

2 に答える 2

5

これを理解するのにかなりの時間を費やしたので、将来誰かがこの投稿に出くわした場合に備えて共有すると思いました.

最初、私はオンでしたhttpcore-nio 4.1が、接続を確立することは不可能に思えました。最終的に、私はリフレクション ハックを使用してそれを行いました (これはおそらく最善の方法ではありません)。4.2.1 にアップグレードした後は、かなり簡単になりました。以下で両方のソリューションを共有します。403 Forbidden接続しているクライアントが localhost でない場合、次のコードが返されます。

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プライベート フィールド ( ) を取得するための恐ろしい、恐ろしいリフレクション ハックです。 iosessionHttpContext

@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);
    } 
    ...
}
于 2012-07-15T21:13:40.873 に答える
1

反対側のエンドポイントの IP を取得するために、NHttpConnectionインスタンスを型にキャストしてメソッドHttpInetConnectionを呼び出すことができます。HttpInetConnection#getRemoteAddress接続オブジェクトはHttpContext、パラメータとして に渡されたインスタンスから取得できますHttpRequestHandlerEventListenerまたは、プロトコル処理ロジックから接続ライフ サイクル イベント ログを分離する場合は、インターフェイスを実装することをお勧めします。

また、HttpCore の contrib パッケージには一連のロギング クラスがあり、ワイヤおよび I/O イベント ロギング機能を使用して標準の HttpCore クラスを拡張するために使用できます。

http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/httpcore-contrib/src/main/java/org/apache/http/contrib/logging/

于 2011-06-15T11:43:05.247 に答える