Vertx Streaming zip 文件到 http 响应
Vertx Streaming zip file to http response
我正在尝试流式传输 zip 文件作为输出以供用户下载。我创建了一个 zipOutputStream,并尝试将它发送到 vertx http 响应中。
然而,此下载损坏的 zip 文件或挂起
public void download(RoutingContext routingContext) {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos)) {
for (int i = 0; i < 2; i++) {
String fileName = "test" + i + ".csv";
File tempFile = createTempFile("test" + i);
tempFile.deleteOnExit();
InputStream is = new FileInputStream(tempFile);
byte[] buffer = new byte[is.available()];
is.read(buffer);
ZipEntry entry = new ZipEntry(fileName);
zos.putNextEntry(entry);
try {
zos.write(buffer, 0, buffer.length);
zos.closeEntry();
String b64String = Base64.encodeBase64String(baos.toByteArray());
routingContext.response()
.setChunked(true)
.putHeader(HttpHeaders.CONTENT_TYPE, "application/zip")
.putHeader("Content-Disposition", "attachment; filename=\"test.zip\"")
.putHeader(HttpHeaders.TRANSFER_ENCODING, "chunked")
.putHeader(HttpHeaders.CONTENT_LENGTH, Long.toString(b64String.length()));
routingContext.response().write(b64String);
routingContext.response().end();
routingContext.response().close();
} finally {
baos.close();
}
}
}
catch(Exception ex) {
}
}
我想出了解决办法。我将顶点 httpResponse 包装在一个 outputStream 中,并将其推送到 zipOutputStream 中。通过将 chunked 设置为 true,它起作用了。
对于非常大的文件,您可以使用流式传输来避免将它们完全加载到 RAM 中:
AsyncInputStream fileContent = new AsyncInputStream(routingContext.vertx(), fileInputStream);
fileContent.endHandler((ev) -> {
routingContext.response().end();
});
Pump.pump(fileContent, routingContext.response()).start();
不幸的是,AsyncInputStream(InputStream 到 ReadStream 的包装器)还不是 VertX 框架的一部分,因此您必须自己实现它或找到一些开源实现。
我正在尝试流式传输 zip 文件作为输出以供用户下载。我创建了一个 zipOutputStream,并尝试将它发送到 vertx http 响应中。
然而,此下载损坏的 zip 文件或挂起
public void download(RoutingContext routingContext) {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos)) {
for (int i = 0; i < 2; i++) {
String fileName = "test" + i + ".csv";
File tempFile = createTempFile("test" + i);
tempFile.deleteOnExit();
InputStream is = new FileInputStream(tempFile);
byte[] buffer = new byte[is.available()];
is.read(buffer);
ZipEntry entry = new ZipEntry(fileName);
zos.putNextEntry(entry);
try {
zos.write(buffer, 0, buffer.length);
zos.closeEntry();
String b64String = Base64.encodeBase64String(baos.toByteArray());
routingContext.response()
.setChunked(true)
.putHeader(HttpHeaders.CONTENT_TYPE, "application/zip")
.putHeader("Content-Disposition", "attachment; filename=\"test.zip\"")
.putHeader(HttpHeaders.TRANSFER_ENCODING, "chunked")
.putHeader(HttpHeaders.CONTENT_LENGTH, Long.toString(b64String.length()));
routingContext.response().write(b64String);
routingContext.response().end();
routingContext.response().close();
} finally {
baos.close();
}
}
}
catch(Exception ex) {
}
}
我想出了解决办法。我将顶点 httpResponse 包装在一个 outputStream 中,并将其推送到 zipOutputStream 中。通过将 chunked 设置为 true,它起作用了。
对于非常大的文件,您可以使用流式传输来避免将它们完全加载到 RAM 中:
AsyncInputStream fileContent = new AsyncInputStream(routingContext.vertx(), fileInputStream);
fileContent.endHandler((ev) -> {
routingContext.response().end();
});
Pump.pump(fileContent, routingContext.response()).start();
不幸的是,AsyncInputStream(InputStream 到 ReadStream 的包装器)还不是 VertX 框架的一部分,因此您必须自己实现它或找到一些开源实现。