Java servlet:为什么PrintWriter.flush()不刷新?

Java servlet:为什么PrintWriter.flush()不刷新?,java,tomcat,servlets,comet,Java,Tomcat,Servlets,Comet,我目前正在编写一个Comet应用程序,它要求我在持久连接上一次发送数据块。但是,在关闭连接之前,我无法将消息刷新到客户端。是否有任何原因导致PrintWriter.flush()方法的行为与我认为的不一样 这是我的Tomcat Comet实现: public void event(CometEvent event) throws IOException, ServletException { HttpServletRequest request = event.getHttpServle

我目前正在编写一个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();
    }
}
public void事件(CometEvent事件)抛出IOException、ServletException{
HttpServletRequest=event.getHttpServletRequest();
HttpServletResponse=event.getHttpServletResponse();
if(event.getEventType()==EventType.BEGIN){
setAttribute(“org.apache.tomcat.comet.timeout”,300*1000);
PrintWriter out=response.getWriter();
out.println(“开始!”);
out.flush();
System.out.println(“EventType.BEGIN”);
}else if(event.getEventType()==EventType.READ){
InputStream=request.getInputStream();
字节[]buf=新字节[512];
做{
int n=is.read(buf);//可以引发IOException
如果(n>0){
System.out.println(“读取”+n+”字节:“+新字符串(buf,0,n)
+对于会话:“+request.getSession(true.getId());
}else if(n<0){
返回;
}
}而(is.available()>0);
System.out.println(“子类型:+event.getEventSubType());
System.out.println(“EventType.READ”);
}else if(event.getEventType()==EventType.END){
PrintWriter out=response.getWriter();
out.println(“结束!”);
out.close();
System.out.println(“checkError:+out.checkError());
System.out.println(event.getEventSubType());
System.out.println(“EventType.END”);
//enqueue(newendEvent(请求、响应));
}else if(event.getEventType()==EventType.ERROR){
PrintWriter out=response.getWriter();
out.println(“错误!”);
out.flush();
System.out.println(“checkError:+out.checkError());
System.out.println(“子类型:+event.getEventSubType());
//response.getWriter().close();
System.out.println(“EventType.ERROR”);
}否则{
(新的ServletException(“异常”)).printStackTrace();
}
}

因此,在这里,我试图发送消息“开始!”并在之后保持连接打开,以便发送更多数据。但是,在连接关闭之前,消息似乎不会通过

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

运行此代码后,Firebug告诉我这是响应头: 服务器:ApacheCoote/1.1 传输编码:分块 日期:2009年7月13日星期一格林尼治标准时间21:16:29


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

我记得servlet存在一个问题,如果页面被重定向(如错误页面),当前的响应缓冲区writer(在本例中为writer)将被丢弃而不被写入

我不太懂笑话

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


这是什么意思?此外,您可能希望查看api中的available()。我不认为它做了你认为它做的事。

所以看起来浏览器一直在接收数据,但因为连接没有关闭,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);

传统上,人们只处理第四个readyState,这意味着传输已完成。然而,在我的例子中,我需要在传输结束之前读取数据。因此,我需要代码来处理第三个readyState。

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

两个电话都没有出去

writer.flush();
writer.end();
当我试图做一个
response.flushBuffer()
时,除了上面两个之外,还抛出了一个
java.nio.charset.UnmappableCharacterException
(在jboss 5.1下)。然后我添加了一个
response.setCharacterEncoding(“UTF-8”);
问题就解决了


这可能与你的问题无关,但因为我在谷歌找到了你的第一篇帖子,我在这里为有同样情况的人回答。

所以我在这里尝试发送消息“开始!“然后保持连接打开,以便我可以发送更多数据。但是,在连接关闭之前,消息似乎不会通过。好的,请尝试response.flushBuffer()?如果这不起作用,请尝试再写入大量字节。您使用的是哪种连接器APR或NIO?firebug不也应该告诉您响应中的内容吗?看起来您只是得到了响应头。