2016-12-12 5 views
0

Tomcat에 비동기 서블릿을 구현하려고합니다. HttpSessionAttributeListener.attributeReplaced()이 트리거 될 때마다 클라이언트에 업데이트를 보냅니다. 클라이언트 쪽에서 서버 보낸 이벤트를 받도록 구성됩니다.HttpServlet에서 AsyncContext로 응답이 없습니다.

수신기는 업데이트를 수신하지만 브라우저는 응답을받지 못합니다. 브라우저의 개발자 창에 요청이 pending이고 AsyncContext.setTimeout()으로 설정된 시간 초과 후 오류 500으로 끝납니다. 나는 아이디어가 없어 졌는데, 왜 이런 일이 일어나고 있는지.

JS

var source = new EventSource('/acount/sse'); 

source.onmessage = function (event) { 
    console.log(event.data); 
    document.querySelector('#messageArea p').innerHTML += event.data; 
}; 

그리고 이것은 내 서블릿 코드 :

서블릿

public class SSE extends HttpServlet implements HttpSessionAttributeListener { 

    public static final String ATTR_ENTRY_PROCESSOR_PROGRESS = "entryProcessorProgress"; 

    private AsyncContext aCtx; 

    @Override 
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 

     req.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true); 

     resp.setContentType("text/event-stream"); 
     resp.setHeader("Cache-Control", "no-cache"); 
     resp.setHeader("Connection", "keep-alive"); 
     resp.setCharacterEncoding("UTF-8"); 

     aCtx = req.startAsync(req, resp); 
     aCtx.setTimeout(80000); 

    } 

    @Override 
    public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) { 
     write(httpSessionBindingEvent); 
    } 

    @Override 
    public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) { 

    } 

    @Override 
    public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) { 
     write(httpSessionBindingEvent); 
    } 

    private void write(HttpSessionBindingEvent httpSessionBindingEvent) { 
     if (httpSessionBindingEvent.getName().equals(ATTR_ENTRY_PROCESSOR_PROGRESS)) { 
      try { 
       String message = "data: " + httpSessionBindingEvent.getValue() + "\n\n"; 
       aCtx.getResponse().getWriter().write(message); 
       aCtx.getResponse().getWriter().flush(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 

     } 
    } 


} 

답변

0

문제 :

난 당신의 코드를 시도하고있는 java.lang.NullPointerException이 있었다 다음 aCtx가 null이기 때문에

aCtx.getResponse().getWriter().write(message); 

은.

서블릿과 수신기가 혼합되어 있지만 Listeners 메서드가 호출 될 때 AsyncContext 초기화는 수행되지 않습니다. 따라서 nothings는 브라우저로 이동합니다.

서블릿에 리스너를 삽입하고 세션 속성을 통해 AsychContext 객체를 밀입국시켰다. 그래서 청취자가 접근 할 수있었습니다.

그리고 작동합니다.

완전한 코드 :

html로 :

<!DOCTYPE html> 
<html> 
<head> 
<meta charset="UTF-8"> 
<title>Server Event Listener</title> 
</head> 
<body> 
<div id="messageArea"> 
<p></p> 
</div> 
<script> 
var source = new EventSource('/yourPath/ServerSentEvent'); 

source.onmessage = function (event) { 
    console.log(event.data); 
    document.querySelector('#messageArea p').innerHTML += event.data; 
}; 
</script> 
</body> 
</html> 

서블릿 :

package testingThings.ServerSentEvent; 

import java.io.IOException; 

import javax.servlet.AsyncContext; 
import javax.servlet.ServletException; 
import javax.servlet.annotation.WebServlet; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

@WebServlet(asyncSupported = true, value = {"/ServerSentEvent"}) 
public class ServerSentEvent extends HttpServlet { 
    private static final long serialVersionUID = 1L; 

    @Override 
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 

     // add @WebServlet(asyncSupported = true) instead 
     // http://stackoverflow.com/questions/7855712/how-to-avoid-request-set-async-supported-true-to-enable-async-servlet-3-0-proces 
     // req.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true); 

     resp.setContentType("text/event-stream"); 
     resp.setHeader("Cache-Control", "no-cache"); 
     resp.setHeader("Connection", "keep-alive"); 
     resp.setCharacterEncoding("UTF-8"); 

     AsyncContext aCtx = req.startAsync(req, resp); 
     aCtx.setTimeout(80000); 

     // add a asyncContext a session Attribute 
     req.getSession().setAttribute("asyncContext", aCtx); 

     //start logging in listener 
     req.getSession().setAttribute("entryProcessorProgress", "trigger output"); 
    } 
} 

HttpSessionAttributeListener에 :

package testingThings.ServerSentEvent; 

import java.io.IOException; 

import javax.servlet.AsyncContext; 
import javax.servlet.annotation.WebListener; 
import javax.servlet.http.HttpSessionAttributeListener; 
import javax.servlet.http.HttpSessionBindingEvent; 

@WebListener 
public class SessionAttributeListener implements HttpSessionAttributeListener { 

    public static final String ATTR_ENTRY_PROCESSOR_PROGRESS = "entryProcessorProgress"; 

    @Override 
    public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) { 
     write(httpSessionBindingEvent); 
    } 

    @Override 
    public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) { 

    } 

    @Override 
    public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) { 
     write(httpSessionBindingEvent); 
    } 

    private void write(HttpSessionBindingEvent httpSessionBindingEvent) { 
     if (httpSessionBindingEvent.getName().equals(ATTR_ENTRY_PROCESSOR_PROGRESS)) { 
      try { 
       // get the AsyncContext from the session 
       AsyncContext aCtx = (AsyncContext) httpSessionBindingEvent.getSession().getAttribute("asyncContext"); 
       String message = "data: " + httpSessionBindingEvent.getValue() + "<br>\n\n"; 
       aCtx.getResponse().getWriter().write(message); 
       aCtx.getResponse().getWriter().flush(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 
+1

감사합니다. –