2014-08-29 49 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