更改Netty 4 HTTP文件服务器示例以使用ChunkedStream而不是ChunkedFile [英] Changing Netty 4 HTTP File Server example to use ChunkedStream instead of 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屋!