2014-08-29 1 views
2

서버의 Java Serlvet을 사용하여 Webapp에 Server-Sent-Event를 구현하려고합니다.Java Servlet 및 SSE에서 연결이 닫습니다.

클라이언트가 연결을 닫았다는 것을 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; 
     }; 
    } 

서버 코드

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

나에게 보인다는 오류 상태를 확인합니다. 또는 혜성. – kaqqao

+0

'지속 연결'을 계속해서 열어 두는 것이 좋습니다. 그렇지 않으면 기본적으로 서버에서 모든 데이터를 전송 한 후에 연결을 닫아야한다고 생각합니다. 영구 연결을 만들려면 http://stackoverflow.com/questions/3304006/persistent-httpurlconnection-in-java – Jason

답변

0

는 연결이 클라이언트에 의해 닫혀 있는지 서블릿에서 확인 할 수 있습니까?

가 결국 예외가 발생합니다 : 어느 쪽 IOException: connection reset 컨테이너는 고정 길이를 사용하지 않을 때 않는 메모리로 스트리밍되는 경우 소켓, 또는 OutOfMemoryError에 직접 스트리밍하는 경우 또는 청크 전송 모드.

클라이언트 브라우저가 닫힌 경우에도 서블릿 while (true)는 무한대입니다.

아니 그렇지 않습니다.

+1

예, 그렇습니다 :). 예외는 발생하지 않습니다. 나는 또한 그것을 기대했다. 응용 프로그램 서버 사용 : WebSphere Application Server 리버티 프로파일 –

+0

안녕하십니까, @ sasha_trn,이 문제에 대한 귀하의 결론을 알려 주실 수 있습니까? 감사! – Ricardo

+1

안녕하세요 @ 리카르도, 오래 전이었습니다. AFAIR, 클라이언트에 의한 연결 종료를 결정하는 방법을 찾지 못했습니다. 무한 루프없이 코드를 변경했습니다. –

0

확인하는 한 가지 방법은 Servlet인데 연결이 닫혀있는 경우 writer.checkError() 메서드를 사용하고 있습니다. 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()는 말한다 :

이 닫혀지지 않은 경우는, 그 스트림을 플래시 및 WebSocket을 다시 구현하려는처럼

+0

내 친구 인 Shuge Li와 Enyong Chen에 대한 크레딧은 아직이 커뮤니티에 없습니다. – Ricardo

관련 문제