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 框架的一部分,因此您必须自己实现它或找到一些开源实现。