2014-08-29 46 views
2

我尝试在服务器上使用Java Serlvet在Webapp中实现Server-Sent-Event。Java Servlet和SSE中的连接关闭

是否可以在Servlet中检查连接是否被客户端关闭?即使客户端浏览器关闭,Servlet中的循环while(true)也是无限的。

客户端代码

function startLogSSE(lastEventId, level) { 
     var eventSource = new EventSource("log-sse?last-event-id=" + lastEventId + "&level=" + level); 
     eventSource.onmessage = function (event) { 
      document.getElementById('log').innerHTML = event.data + "\n" + document.getElementById('log').innerHTML; 
     }; 
    } 

Server代码

public class LogSSEServlet extends HttpServlet { 
    private static final Logger logger = LoggerFactory.getLogger(LogSSEServlet.class); 

    @Override 
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
     response.setContentType("text/event-stream"); 
     response.setCharacterEncoding("UTF-8"); 

     PrintWriter writer = response.getWriter(); 

     // get logger purgerDB appender 
     PurgerDBAppender appender = LogUtils.getPurgerDBAppender(); 
     if (appender == null) { 
      writer.write("data: [ERROR] Appender 'purgerDB' isn't found for logger 'com.bp3'\n\n"); 
      writer.close(); 
      return; 
     } 

     int eventId = 0; 
     // get last-event-id 
     String lastEventId = request.getHeader("last-event-id"); 
     if (lastEventId == null) { 
      // try to get lastEventId from parameter 
      lastEventId = request.getParameter("last-event-id"); 
     } 
     if (lastEventId != null) { 
      try { 
       eventId = Integer.parseInt(lastEventId); 
      } catch (NumberFormatException e) { 
       logger.error("Failed to parse last-event-id: " + lastEventId); 
      } 
     } 
     String minLevel = request.getParameter("level"); 
     if (minLevel == null) { 
      minLevel = "TRACE"; 
     } 

     // get logs from purgerDB logger appender 
     LogServices logServices = new LogServices(); 
     try { 
      logServices.open(); 
     } catch (SQLException e) { 
      throw new ServletException(e); 
     } 
     try { 
      while (true) { 
       List<LogMessage> messages = logServices.getLastMessages(Level.toLevel(minLevel), eventId, 0); 
       if (messages.size() > 0) { 
        writer.write("id: " + messages.get(0).getEventId() + "\n"); 
        writer.write("data: " + LogUtils.formatLog(messages) + "\n"); 
        writer.flush(); 
       } 
       try { 
        Thread.sleep(100); 
       } catch (InterruptedException e) { 
        break; 
       } 
      } 
     } catch (SQLException e) { 
      throw new ServletException(e); 
     } finally { 
      logServices.closeQuietly(); 
     } 
    } 
} 
+0

我看来,像你想重新实现的WebSockets。或彗星。 – kaqqao 2014-08-29 18:58:05

+0

如果您试图保持打开状态,请在“持续连接”上进行一些搜索,否则默认情况下,我认为一旦服务器传输完所有数据后应关闭连接。 创建持久连接请参阅http://stackoverflow.com/questions/3304006/persistent-httpurlconnection-in-java – Jason 2014-09-02 23:38:57

回答

0

是否有可能在Servlet来检查连接是由客户端关闭?

最后一个将引发异常:要么一个IOException: connection reset如果直接流传输到所述插座,或OutOfMemoryError如果容器流至存储器,其中,当不使用固定长度或不分块传输模式。

即使客户端浏览器关闭,Servlet中while(true)的循环也是无限的。

不,它不是。

+1

是的,它是:)。没有例外被抛出。我也期待它。 使用的应用程序服务器:WebSphere Application Server Liberty Profile – 2014-09-06 21:01:26

+0

嗨,@sasha_trn,您可以与我们分享您对此问题的结论吗?谢谢! – Ricardo 2015-07-08 23:47:08

+1

嗨@Ricardo,很久以前。 AFAIR,我没有找到确定客户端连接关闭的方法。我改变了我的代码,没有无限循环。 – 2015-07-09 13:26:19

0

使用writer.checkError()方法检查连接是否已关闭的一种方法是验证Servlet。我在Chrome上测试了这个修补程序,它可以正常工作您的代码将是:

  boolean error=false; 
      while (!error) { 
       //...     
       writer.write("data: " + /*...*/ "\n"); 
       //writer.flush(); 
       error = writer.checkError(); //internally calls writer.flush() 
      } 

详细

PrintWriter's API说:

方法在这个类不会抛出I/O异常,尽管它的一些 构造的可能。客户可以通过调用checkError()来询问是否发生了错误 。

checkError()说:

刷新流,如果没有关闭,并检查其错误状态

+0

学分给我的朋友Shuge Li和Enyong Chen,还没有在这个社区。 – Ricardo 2015-07-29 23:18:48