更改Netty 4 HTTP文件服务器示例以使用ChunkedStream而不是ChunkedFile [英] Changing Netty 4 HTTP File Server example to use ChunkedStream instead of ChunkedFile

查看:1546
本文介绍了更改Netty 4 HTTP文件服务器示例以使用ChunkedStream而不是ChunkedFile的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我总数据大小未知时,我正试图围绕Netty 4实现一个使用分块传输编码服务HttpResponses主体的HTTP服务器。

I'm trying to wrap my head around Netty 4 way of implementing a HTTP Server that serve HttpResponses bodies using chunked transfer-encoding when total data size is unknown.

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

As a starting point, I simply changed the HttpStaticFileServerHandler (found in https://github.com/netty/netty/tree/netty-4.0.0.CR1/example/src/main/java/io/netty/example/http/file) to use a ChunkedStream instead of a ChunkedFile (they both are ChunkedByteInputs).

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

I understand that it is not ideal in the original example use case to use a FileInputStream but I think it makes a good example reusing already known code.

所以,这里是来自io.netty.example.http.file包的HttpStaticFileServerHandler类的差异(对比4.0.0.CR1):

So, here is the diff against the HttpStaticFileServerHandler class from the io.netty.example.http.file package (vs. 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)) {

这里是完整更改的文件:< a href =https://gist.github.com/eskatos/5311587\"rel =nofollow> https://gist.github.com/eskatos/5311587

And here the complete changed file: https://gist.github.com/eskatos/5311587

更改是最小的:使用FileInputStream而不是RandomAccessFile和ChunkedStream而不是ChunkedFile。管道未受影响。

Changes are minimal: use a FileInputStream instead of RandomAccessFile and ChunkedStream instead of ChunkedFile. The pipeline is untouched.

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

To reproduce, simply apply the changes to the Netty example, run it and try do download any file.

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

After this change, directory listing obviously works because reponses are not chunked but file downloads don't. The client download the file but never finish the download, hold the connection and wait forever. I've tried several from browsers to curl, wget etc.. I've also tried to add a ByteLoggingHandler to the pipeline and I can see an empty trailing chunk so I don't understand why the browser still wait for data.

任何线索?

推荐答案

为了终止未知的分块转移size(Content-Length未知,因此未指定)您只需将空块作为最后一个块发送。这允许保持连接打开以支持Keepalive:

In order to terminate a chunked transfer of unkown size (Content-Length not known and thus not specified) you simply send an empty chunk as last chunk. This permits to keep the connection open in order to support keepalives:

        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

Here is a complete example: https://github.com/scireum/sirius/blob/develop/web/src/sirius/web/http/Response.java#L649

这篇关于更改Netty 4 HTTP文件服务器示例以使用ChunkedStream而不是ChunkedFile的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆