如何在 gzip header 之后在 spark java 中正确设置 content-length

How to correctly set content-length in spark java after gzip header

我正在使用 Spark 来提供不同类型的内容。 “Content-Length”计算正确,但我在使用时遇到问题:

response.header("Content-Encoding", "gzip")

根据 their documentation,当设置 header 时,spark 会自动对内容进行 gzip 压缩...它确实做到了。

但是,我之前计算的“Content-Length”不再有效,因此我在浏览器中收到 'net::ERR_CONTENT_LENGTH_MISMATCH' 错误。

自己对其进行 Gzip 压缩,并且无法计算结果大小,因为 spark 会再次压缩输出。

我如何知道 spark 压缩输出后的结果大小是多少?

更多详情:

我在 Spark 上创建了一个库,它自动设置了这样的 headers,有趣的部分看起来像(简化):

if(request.headers("Accept-Encoding")?.contains("gzip")) {
    response.header("Content-Encoding", "gzip")
    // How to get or calculate the resulting size?
    response.header("Content-Length", ???????)
}

问题是 Spark 没有自动设置“Content-Length”header,所以我正在尝试添加它。直到那时计算都是正确的(没有压缩),但是由于 Spark 将压缩输出(因为它检测到“gzip”作为编码),我没有可靠的方法来正确设置它。

我能想到的解决这个问题的方法是:

  1. 等到 Spark adds that header automatically(或滚动我自己的分支)。
  2. 找到一种在 Spark 压缩输出后获得该大小的方法。
  3. 以与 Spark 相同的方式压缩它,这样我就可以计算大小(但很难看,因为它会将输出压缩两次 == CPU 浪费)。

我目前的解决方案是在使用 gzip header 时不设置 Content-Length header (但对于 large-size 文件作为浏览器来说并不理想不知道已经下载了多少百分比)。

我希望这些细节能使情况更加明朗。

感谢您的澄清!

  1. 是的,现在您手动添加它,这就是我要做的并保持这种方式,除非您确实需要 Content-Length 用于您的用例。不知道大小有点烦人,但并不少见。
  2. 我很确定使用当前 spark 的内部 API 很难做到这一点。我昨天玩过它,用 apache commons CountingOutputStream 拦截 OutputStreams 并且没有 API 在不更改代码的情况下做到这一点并且它还有其他问题。问题还在于,在 spark 压缩输出之后,它很可能已经被发送刷新并发送回客户端,但是这个 header 必须在数据之前发送。在发送数据之前你基本上必须知道这一点,所以这是最难的方法。
  3. 是的,最容易实现 spark 的方法可能是为他提供已经准备好的压缩数据作为 ByteArray(好像您正在使用 kotlin)并禁用 auto-compression。 ByteArrayOutputStream 是个好方法。这样它至少只被压缩一次。还有关于设置 Content-Encoding header 的事情,同时强制 spark 不编码,但这是简单的补丁。丑陋的是,你必须将整个数据存储在内存中+服务器不会在这一切都是 pre-calculated 之前开始发送数据,所以用户点击下载和下载开始之间会有延迟。
  4. 如果您的大文件将被多次使用,您可以 pre-calculate 提前或先 运行 压缩它们的大小并缓存该信息。这样您就可以将数据直接发送到流中,并且在开始时就知道信息。