Java Servlets:为什么PrintWriter.flush()没有刷新?

时间:2009-07-13 21:20:01

标签: java tomcat servlets comet

我目前正在编写一个Comet应用程序,它要求我在持久连接上一次发送数据块。但是,在关闭连接之前,我无法将消息刷新到客户端。是否有任何理由PrintWriter.flush()方法的行为不像我认为的那样?

这是我的Tomcat Comet实现:

public void event(CometEvent event) throws IOException, ServletException {
    HttpServletRequest request = event.getHttpServletRequest();
    HttpServletResponse response = event.getHttpServletResponse();
    if (event.getEventType() == EventType.BEGIN) {
        request.setAttribute("org.apache.tomcat.comet.timeout", 300 * 1000);
        PrintWriter out = response.getWriter();
        out.println("BEGIN!");
        out.flush();
        System.out.println("EventType.BEGIN");
    } else if (event.getEventType() == EventType.READ) {
        InputStream is = request.getInputStream();
        byte[] buf = new byte[512];
        do {
            int n = is.read(buf); //can throw an IOException
            if (n > 0) {
                System.out.println("Read " + n + " bytes: " + new String(buf, 0, n) 
                        + " for session: " + request.getSession(true).getId());
            } else if (n < 0) {

                return;
            }
        } while (is.available() > 0);
        System.out.println("subtype: "+event.getEventSubType());
        System.out.println("EventType.READ");
    } else if (event.getEventType() == EventType.END) {
        PrintWriter out = response.getWriter();
        out.println("END!");
        out.close();
        System.out.println("checkError: "+out.checkError());
        System.out.println(event.getEventSubType());
        System.out.println("EventType.END");
        //eventWorker.enqueue(new EndEvent(request, response));
    } else if (event.getEventType() == EventType.ERROR) {
        PrintWriter out = response.getWriter();

        out.println("ERROR!");
        out.flush();
        System.out.println("checkError: "+out.checkError());
        System.out.println("subtype: "+event.getEventSubType());

        //response.getWriter().close();
        System.out.println("EventType.ERROR");
    } else {
        (new ServletException("EXCEPTION")).printStackTrace();
    }
}

所以我在这里尝试发送消息“开始!”然后保持连接打开,这样我就可以发送更多数据。但是,似乎在连接关闭之前消息才会通过。

这是我的ajax代码: $ .post('comet',function(data){alert(data);});

运行此代码后,Firebug告诉我这是响应头: 服务器:Apache-Coyote / 1.1 转移编码:分块 日期:2009年7月13日星期一21:16:29 GMT

这让我觉得我的浏览器收到了一些数据,但是如何在连接关闭之前更新页面上的内容?

4 个答案:

答案 0 :(得分:3)

因此,浏览器似乎一直在接收数据,但由于连接未关闭,JavaScript思想数据仍在发送。这就是为什么我的jQuery回调函数没有被调用。

查看W3C AJAX教程,我注意到XMLHttpRequest对象有不同的就绪状态。

var xmlhttp;
    if (window.XMLHttpRequest)
      {
      // code for IE7+, Firefox, Chrome, Opera, Safari
      xmlhttp=new XMLHttpRequest();
      }
    else if (window.ActiveXObject)
      {
      // code for IE6, IE5
      xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
      }
    else
      {
      alert("Your browser does not support XMLHTTP!");
      }
    xmlhttp.onreadystatechange=function()
    {
        if(xmlhttp.readyState==3) {
            alert('process '+xmlhttp.responseText);
        }
        if(xmlhttp.readyState==4) {
            alert('ready '+xmlhttp.responseText);
        }
    }
    xmlhttp.open("GET","comet",true);
    xmlhttp.send(null);

传统上,人们只处理第4个readyState,这意味着传输已完成。但是,在我的情况下,我需要在传输结束之前读取数据。因此,我需要代码来处理第3个readyState。

答案 1 :(得分:0)

我记得servlet存在问题,如果你的页面被重定向(比如错误页面),那么当前的响应缓冲区(在这种情况下是编写器)会被丢弃而不会被写入。

答案 2 :(得分:0)

我并没有真正追随妙语。

  

因此,一旦出现错误并且连接关闭,我会看到我之前尝试发送的所有消息。

这是什么意思?此外,您可能想要查看api for available()。我不认为它符合你的想法。

答案 3 :(得分:0)

我遇到了几乎相同的问题:

两个电话都没有出去。

writer.flush();
writer.end();

当我尝试在上面两个之外做response.flushBuffer()时,抛出java.nio.charset.UnmappableCharacterException(在jboss 5.1下)。然后我添加了一个response.setCharacterEncoding("UTF-8);,问题就消失了。

这可能与您的问题无关,但由于我发现您的帖子是谷歌的第一个,我在这里为具有相同情况的人回答。