问题描述
|
我正在使用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);
}
...
}