Java 如何使用Netty编写一个异步HttpServer

Java 如何使用Netty编写一个异步HttpServer,java,netty,Java,Netty,我正在尝试创建一个简单的异步Netty HTTP服务器。我需要支持的关键特性是能够将封装在事件中的HttpRequest发送到事件驱动组件(在同一JVM中),该组件将处理事件并生成响应。此事件驱动组件在Netty组件的单独线程中运行 我遵循了许多示例来构建一些应该适合我的东西,并且当响应与处理程序在同一个线程中生成时,我所拥有的东西也可以工作 我编写/改编的自定义处理程序是: private class WebServerHandler extends SimpleChannelInbo

我正在尝试创建一个简单的异步Netty HTTP服务器。我需要支持的关键特性是能够将封装在事件中的HttpRequest发送到事件驱动组件(在同一JVM中),该组件将处理事件并生成响应。此事件驱动组件在Netty组件的单独线程中运行

我遵循了许多示例来构建一些应该适合我的东西,并且当响应与处理程序在同一个线程中生成时,我所拥有的东西也可以工作

我编写/改编的自定义处理程序是:

    private class WebServerHandler extends SimpleChannelInboundHandler<Object> {
        String uri;
        @Override
        public void messageReceived(final ChannelHandlerContext ctx, final Object msg) {
            if (!(msg instanceof FullHttpRequest)) return;

            final FullHttpRequest request = (FullHttpRequest) msg;

            uri = request.uri();
            System.out.println("Handling: " + uri);
            if (HttpUtil.is100ContinueExpected(request)) send100Continue(ctx);

            final Handler handler = WebServer.this.getHandler(request.uri());
            if (handler == null) {
                writeNotFound(ctx, request);
            } else {
                try {
                    handler.handle(ctx, request);
                } catch (final Throwable ex) {
                    ex.printStackTrace();
                    writeInternalServerError(ctx, request);
                }
            }
        }

        @Override
        public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) {
            ctx.close();
        }

        @Override
        public void channelReadComplete(final ChannelHandlerContext ctx) {
            System.out.println("Completed: " + uri);
//          ctx.flush();
        }
    }
我没有包含事件驱动组件的任何信息,因为它是一个大型而复杂的系统(实际上是一种编程语言),但我知道相关代码正在成功调用。我试图执行以生成响应的实际代码是:

File file = new File(file_uri);
System.out.println("file: " + file.getAbsolutePath());
RandomAccessFile raf = new RandomAccessFile(file, "r");
HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
HttpUtil.setContentLength(response, raf.length());

ctx.write(response); 
ctx.write(new DefaultFileRegion(raf.getChannel(), 0, file.length())); 
ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);

raf.close();

所以,我的问题是-在我发送响应之前,如何阻止Netty调用
channelReadComplete(…)
方法?

我认为您的
raf.close
调用应该在附加到文件写入的侦听器中。如前所述,我希望您在write调用有机会读取所有文件之前关闭该文件。您的响应正确地设置了内容长度,但是如果您没有写入那么多字节,因为您提前关闭了文件,那么您的客户端将挂起等待其余的字节

您应该在管道中的聚合器之前移动编码器。聚合器可以发送编码器需要编码的响应。考虑使用,因为它可以用一个处理程序替换编码器/解码器

您可以使用对象作为类型扩展SimpleChannelInboundHandler,但随后拒绝FullHttpRequest消息之外的任何消息。如果您更改扩展中的类型,那么(您是否使用Netty 5?为什么?)

例如:

... extends SimpleChannelInboundHandler<FullHttpRequest> {
...
public void messageReceived(ChannelHandlerContext ctx, FullHttpRequest request) {
。。。扩展SimpleChannelInboundHandler{
...
收到公共无效消息(ChannelHandlerContext ctx,FullHttpRequest请求){

我不认为早期调用
channelReadComplete
对您的场景很重要。因为您已经在读取/响应处理程序中刷新了
channelReadComplete

非常感谢您-raf.close()的放置在一个听众中修复了我的问题。谢谢你的其他欢迎推荐!
... extends SimpleChannelInboundHandler<FullHttpRequest> {
...
public void messageReceived(ChannelHandlerContext ctx, FullHttpRequest request) {