Servlet:response.setContentLength()减慢下载速度 [英] Servlet: response.setContentLength() slows download down

查看:284
本文介绍了Servlet:response.setContentLength()减慢下载速度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

private void downloadAllRelease(HttpServletRequest request,
        HttpServletResponse response) {
    LoginToken tok=getToken(request, response);
    int size = 0;
    try {
        ArrayList<Release> releases = manager.getReleases(tok.getUsername);
        ZipOutputStream out = new ZipOutputStream(response.getOutputStream());
        for (int i=0; i<releases.size(); i++) {
            size += releases.get(i).getFile().length;
            out.putNextEntry(new ZipEntry(releases.get(i).getFilename()));
            out.write(releases.get(i).getFile());
            out.closeEntry();
        }
        response.setContentLength(size);
        response.setContentType("application/force-download");
        response.setHeader("Content-Disposition","attachment;filename=release.zip");
        out.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

response.setContentLength() 重新减缓下载量。

如果我不使用它或将它放在 out.close()之后,所有内容仍然正常,但下载速度更快。

有人可以解释为什么,如果需要使用 response.setContentLength()

response.setContentLength() reeeeally slows downloads down.
If I don't use It or put it after out.close() everything still works fine but downloads are muuuuch faster.
Can someone explain me why and if it is necessary to use response.setContentLength()?

推荐答案

也许是因为您指定的大小超过实际发送到响应的大小,而webbrowser基本上会感到困惑,等待更多的数据?你知道,ZIP压缩文件并减小最终的大小。

Perhaps because you're specifying a larger size than what is actually been sent to the response and the webbrowser basically get confused and is waiting for more data? You know, ZIP compresses files and reduces the final size.

如果您无法有效计算它,请不要指定响应的内容长度。 servlet容器将自动通过分块编码发送。真的,这有一点开销,让Webbrowser具有未知的下载进度,但是这不需要先在服务器内存中缓冲整个响应,以便您可以获得正确的最终响应内容长度。

Just don't specify the response's content length if you cannot efficiently calculate it beforehand. The servlet container will automatically send it with chunked encoding anyway. True, this has a little more overhead and leaves the webbrowser with an unknown download progress, but this doesn't require you to buffer the entire response in server's memory first so that you can get the proper final response content length.

如果您真的希望计算最终响应内容长度,则需要将其全部写入 ByteArrayOutputStream ,然后通过其 toByteArray()方法获取 byte [] 。真正的响应内容长度是 byte [] 的长度。

If you really want to calculate the final response content length, you'd need to write it all to a ByteArrayOutputStream instead and then get the byte[] by its toByteArray() method. The real response content length is then the length of the byte[].

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream out = new ZipOutputStream(baos);
// ...

byte[] bytes = baos.toByteArray();
response.setContentLength(bytes.length);
response.getOutputStream().write(bytes);

这只是更多的内存占用,因为一切都将存储在服务器的内存中。如果多个用户并发执行此操作,并且zip输出相对较大,那么您的服务器可能会迟早失去内存。作为另一个选择,您可以使用 FileOutputStream 将其写入由 File#createTempFile()创建的临时文件,因此您可以通过 File#length()获取其大小,并使用 FileInputStream 将其直接流式传输到 OutputStream 的响应通常的方式。这只是较慢,因为您基本上将字节传输两次。

This is only more memory hogging because everything will be stored in server's memory first. If multiple users do this concurrently and the zip output is relatively large, then your server might risk to run out of memory sooner or later. As another alternative, you could write it using FileOutputStream to a temp file as created by File#createTempFile(), so that you can obtain its size by File#length() and use FileInputStream to stream it directly into the OutputStream of the response the usual way. This is only slower as you're basically transferring the bytes around twice.

这篇关于Servlet:response.setContentLength()减慢下载速度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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