java - 尽管调用了 flush(),Servlet 仍在缓冲响应

标签 java tomcat servlets

我们有一个系统,其中客户端发出 HTTP GET 请求,系统在后端进行一些处理,压缩结果并将其发送给客户端。由于处理过程可能需要一些时间,我们将其作为包装 response.getOutputStream()ZipOutputStream 发送。

但是,当第一个 ZipEntry 中的数据量特别少,而第二个条目需要很长时间时,客户端使用的浏览器就会超时。我们已经尝试刷新流缓冲区,但在至少 1000 字节写入流之前似乎没有响应发送到浏览器。奇怪的是,一旦发送了前 1000 个字节,随后的刷新似乎工作正常。

我尝试将代码剥离到最基本的部分来举个例子:

protected void doGet(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {
    try {
        ZipOutputStream _zos = new ZipOutputStream( response.getOutputStream());
        ZipEntry _ze = null;
        long startTime = System.currentTimeMillis();
        long _lByteCount = 0;

        response.setContentType("application/zip");

        while (_lByteCount < 2000) {
            _ze = new ZipEntry("foo");
            _zos.putNextEntry( _ze );

            //writes 100 bytes and then waits 10 seconds
            _lByteCount += StreamWriter.write( 
                    new ByteArrayInputStream(DataGenerator.getOutput().toByteArray()),
                    _zos );
            System.out.println("Zip: " + _lByteCount + " Time: " + ((System.currentTimeMillis() - startTime) / 1000));

            //trying to flush
            _zos.finish();
            _zos.flush();
            response.flushBuffer();
            response.getOutputStream().flush();
        }
    } catch (Throwable e) {
        e.printStackTrace();
    }
}

我将浏览器超时设置为大约 20 秒以便于重现。尽管多次写入 100 个字节,但没有任何内容发送到浏览器并且浏览器超时。如果我延长浏览器超时时间,在写入 1000 个字节之前不会发送任何内容,然后浏览器会弹出“你想保存...”对话框。同样,在最初的 1000 字节之后,每增加 100 字节就可以正常发送,而不是缓冲到 1000 字节的 block 。

如果我将 while 条件中的最大字节数设置为 200 左右,它工作正常,只发送 200 个字节。

我该怎么做才能强制 servlet 发回非常小的初始数据量?

最佳答案

事实证明,为了提高效率,缓冲来自流的数据的底层 Apache/Windows IP 堆栈存在限制。由于大多数人都有数据太多的问题,而不是数据太少的问题,所以大多数时候这是正确的。我们最终做的是要求用户请求足够的数据,以便我们在超时之前达到 1000 字节的限制。很抱歉花了这么长时间来回答这个问题。

关于java - 尽管调用了 flush(),Servlet 仍在缓冲响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6984825/

相关文章:

java - 使用Java Play发送HTTP请求(WSClient初始化)

JavaFx文本移动动画

java - 如何从 Tomcat 的 JNDI 获取 PoolingDataSource

mysql - "Confirm Form Resubmission"问题。 MVC servlets JSP javabean

java - 更改 HashMap 值的成员会导致 java.util.ConcurrentModificationException

java - 来自 Linux 客户端的请求出现 SPNEGO/Kerberos No credential found 错误

tomcat - 在 tomcat 上配置 ssl/tls

java - CXF 无 Spring

java - HttpServlet为什么要实现Serializable?

java - 请求参数值中缺少#之后的部分