Tomcat不会刷新响应缓冲区
我在下面的Tomcat 7
上测试了HttpResponse#flushBuffer
和PrintWriter#flush
HttpResponse#flushBuffer
,但似乎响应忽略了它们而不是像预期的那样在线上刷新内容。
import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/HelloServlet") public class HelloServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter pw = response.getWriter(); pw.println("say hi now"); pw.flush(); response.flushBuffer(); try { Thread.sleep(5000); } catch (Exception e) { } pw.println("say bye in 5 seconds"); } }
在延迟之后,浏览器一起显示“hi”和“bye”。 这是不正当行为还是打算?
@编辑
根据@Tomasz Nurkiewicz
的建议,我再次用curl
测试然后问题就消失了。 似乎标准浏览器和tcp/ip monitor
从同一个http响应中打包small pieces of contents
以将它们一起呈现。
@EDIT 2
还观察到HttpResponse#flushBuffer
和PrintWriter#flush
驱动Tomcat 7
发送客户端分块数据 。
flushBuffer()
的API非常精确:
强制将缓冲区中的任何内容写入客户端 。 对此方法的调用会自动提交响应,这意味着将写入状态代码和标头。
因此,根据规范没有实现Tomcat(更积极地缓冲并且如果它们太小则保持刷新)或者客户端(浏览器)在实际呈现之前等待更多输入。
你可以尝试使用curl或nc
吗?
我刚才有同样的问题。 要阻止浏览器等待页面完成加载,然后才能进行任何渲染,您需要从以下开始:
response.setContentType("text/html;charset=UTF-8");
我也有这个问题。 而且我也发现问题随着curl而消失。 通过一些嗅探,结果certificate罪魁祸首是gzip编码。 为了压缩响应,gzip一直等到底层PrintWriter关闭(也就是说,直到写完全响应),然后产生压缩输出。 在客户端,这意味着在完整响应准备好之前,您不会得到任何回复。 另一方面,Curl不向服务器发出Accept-Encoding:gzip,这就是为什么这样做的原因,你可以按照预期正常获得分块输出。
这种现象的一个尚未提及的可能原因是反病毒软件。 我确实在我的机器上观察到相同的行为:服务器发送分块数据,curl工作,普通浏览器没有,并且Fiddler也确认它不是阻止的服务器。 所以过了一段时间我怀疑Sophos(我的雇主使用的反病毒软件)的网络保护干扰,事实上他们确认他们阻止了https://community.sophos.com/kb/en-us/115656除了通常用于流媒体数据的某些mime类型之外,分块数据直到响应完成。
作为快速检查,可以在http://www.pushlets.com上运行HTTP-Push演示。 如果它不起作用,很可能客户端在处理text / html类型的分块数据方面存在一般性问题。