如何使用Netty通过HTTP流式传输响应

3
我正在使用Netty 3.6.6,希望向调用方发送一个大的响应。由于有些情况下响应体会非常大,所以我无法像在ChannelBuffer中那样复制响应体。
我正在将服务器从CXF迁移到Netty,之前,我可以使用CXF提供的OutputStream来写入数据。
我最初尝试只发送没有内容的响应,然后在一系列8k缓冲区中继续向Channel写入数据。这个方法失败了,因为客户端似乎只看到原始响应并且没有数据,于是抱怨了起来。我尝试将响应设置为分块的,但这似乎没有什么作用,设置分块头也是如此,客户端总是看到一个空流。
我看到了3.6.6的文件服务器示例,它与我想做的类似,只不过数据不是文件。我看到了ChunkedStream和NioStream,它们似乎接近我需要的,但它们需要InputStream / ReadableByteChannel,而我有一个OutputStream;我可以尝试使用PipedInput和OutputStreams,但这似乎会引入一个不幸的瓶颈。
我相信有一种方法可以在响应请求时向客户端流式传输大量数据,但除非我有一个文件,否则我看不到如何实现它。
如果连接保持活动状态,你正在流式传输内容,但不知道内容长度,你又该如何让客户端知道响应已经完成呢?在这种情况下,客户端似乎会永远等待连接关闭。
将3.6.6的静态文件服务器示例修改为删除content-length头(只需将其注释掉),指定它是分块响应。
   response.setChunked(true);
   response.setHeader(Names.TRANSFER_ENCODING, Values.CHUNKED);

然后在写完响应后,使用ChunkedNioStream发送文件:

    // Write the initial line and the header.
    ch.write(response);

    final ReadableByteChannel aIn = java.nio.channels.Channels.newChannel(new FileInputStream(file));
    ChannelFuture writeFuture = ch.write(new ChunkedNioStream(aIn));

产生了不期望的行为,客户端只收到几百个字节就停止接收,这基本上是我在我的应用程序中看到的情况。正确的做法似乎只有在使用content-length时才会发生,而这在我的情况下是不可行的。

1个回答

5
当你试图将一个ChunkedNioStream写入ChunkedWriteHandler时,它只会产生一个仅包含ChunkedNioStream内容的流。也就是说,它生成的是ChannelBuffer而不是HttpChunk
由于HttpMessageEncoder仅处理HttpMessageHttpChunk,因此ChunkedNioStream生成的ChannelBuffer绕过了HTTP分块头部附加到线路上,导致浏览器混乱。
为了解决这个问题,你需要实现自己的ChunkedInput,它会生成HttpChunk而不是ChannelBuffer。然而,我必须承认这可能是一个具有挑战性的任务,所以你可能只想分叉HttpMessageEncoder,让它也理解ChannelBuffer并将其视为HttpChunk。请查看HttpMessageEncoder此部分以获取更多信息。

1
这个问题在Netty 4.x中使用ChunkedInput已经解决了,对吗? - St.Antario

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接