【问题标题】:Changing Netty 4 HTTP File Server example to use ChunkedStream instead of ChunkedFile将 Netty 4 HTTP 文件服务器示例更改为使用 ChunkedStream 而不是 ChunkedFile
【发布时间】:2013-03-27 15:00:39
【问题描述】:

我正在尝试围绕 Netty 4 实现 HTTP 服务器的方法,该服务器在总数据大小未知时使用分块传输编码为 HttpResponses 主体提供服务。

作为起点,我只是将 HttpStaticFileServerHandler(在 https://github.com/netty/netty/tree/netty-4.0.0.CR1/example/src/main/java/io/netty/example/http/file 中找到)更改为使用 ChunkedStream 而不是 ChunkedFile(它们都是 ChunkedByteInputs)。

我知道在原始示例用例中使用 FileInputStream 并不理想,但我认为它是重用已知代码的一个很好的示例。

因此,这里是 io.netty.example.http.file 包中的 HttpStaticFileServerHandler 类的差异(与 4.0.0.CR1 相比):

diff --git a/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java b/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java
index 904579b..0d3592f 100644
--- a/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java
+++ b/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java
@@ -27,13 +27,14 @@ import io.netty.handler.codec.http.FullHttpResponse;
 import io.netty.handler.codec.http.HttpHeaders;
 import io.netty.handler.codec.http.HttpResponse;
 import io.netty.handler.codec.http.HttpResponseStatus;
-import io.netty.handler.stream.ChunkedFile;
+import io.netty.handler.stream.ChunkedStream;
 import io.netty.util.CharsetUtil;

 import javax.activation.MimetypesFileTypeMap;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileNotFoundException;
-import java.io.RandomAccessFile;
+import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
 import java.net.URLDecoder;
 import java.text.SimpleDateFormat;
@@ -159,17 +160,15 @@ public class HttpStaticFileServerHandler extends ChannelInboundMessageHandlerAda
             }
         }

-        RandomAccessFile raf;
+        InputStream raf; // Use an InputStream instead of a RandomAccessFile
         try {
-            raf = new RandomAccessFile(file, "r");
+            raf = new FileInputStream(file);
         } catch (FileNotFoundException fnfe) {
             sendError(ctx, NOT_FOUND);
             return;
         }
-        long fileLength = raf.length();

         HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
-        setContentLength(response, fileLength);
         setContentTypeHeader(response, file);
         setDateAndCacheHeaders(response, file);
         if (isKeepAlive(request)) {
@@ -180,7 +179,7 @@ public class HttpStaticFileServerHandler extends ChannelInboundMessageHandlerAda
         ctx.write(response);

         // Write the content.
-        ChannelFuture writeFuture = ctx.write(new ChunkedFile(raf, 0, fileLength, 8192));
+        ChannelFuture writeFuture = ctx.write(new ChunkedStream(raf)); // Use a ChunkedStream instead of a ChunkedFile

         // Decide whether to close the connection or not.
         if (!isKeepAlive(request)) {

这里是完整的更改文件:https://gist.github.com/eskatos/5311587

变化很小:使用 FileInputStream 代替 RandomAccessFile 和 ChunkedStream 代替 ChunkedFile。管道未受影响。

要重现,只需将更改应用到 Netty 示例,运行它并尝试下载任何文件。

在此更改之后,目录列表显然有效,因为响应没有分块,但文件下载却没有。客户端下载文件但从未完成下载,保持连接并永远等待。从浏览器到 curl、wget 等,我已经尝试了几种。我还尝试将 ByteLoggingHandler 添加到管道中,我可以看到一个空的尾随块,所以我不明白为什么浏览器仍在等待数据。

有什么线索吗?

【问题讨论】:

    标签: http netty chunked-encoding http-chunked


    【解决方案1】:

    为了终止未知大小的分块传输(内容长度未知,因此未指定),您只需发送一个空块作为最后一个块。这允许保持连接打开以支持keepalive:

            ctx.write(new ChunkedInputAdapter(new ChunkedStream(raf, 8192)));
            ChannelFuture writeFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
    

    这是一个完整的例子: https://github.com/scireum/sirius/blob/develop/web/src/sirius/web/http/Response.java#L649

    【讨论】:

    【解决方案2】:

    如果你不指定Content-Length header,客户端不知道你发送的内容的长度,因此它会等到服务器关闭连接,直到断开连接之前收到的所有内容都被认为是内容.

    因此,您必须执行以下操作之一:

    1. 添加Content-Length标头
    2. 发送内容后关闭连接
    3. 使用带有Transfer-Encoding: chunked 标头的分块编码发送内容

    【讨论】:

    • HTTP 1.1 允许没有 Content-Length 标头并使用分块编码。 w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4
    • @MikePone:我认为您一定误读了信任的答案。您的评论可以改写为“HTTP 1.1 允许您的选项 #3”,这是真的,但说起来有点奇怪。
    猜你喜欢
    • 2012-07-14
    • 2023-03-05
    • 2023-03-10
    • 2018-02-09
    • 1970-01-01
    • 2020-07-28
    • 2015-04-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多