【问题标题】:No response from HttpServlet with AsyncContext使用 AsyncContext 的 HttpServlet 没有响应
【发布时间】:2017-04-26 20:38:36
【问题描述】:

我正在尝试在 Tomcat 上实现异步 servlet,每次触发 HttpSessionAttributeListener.attributeReplaced() 时都会向客户端发送更新。客户端配置为接收服务器发送事件。

虽然监听器接收到更新,但浏览器没有收到任何响应。浏览器的开发者面板显示,请求是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;
};

这是我的 servlet 代码:

Servlet

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();
            }

        }
    }


}

【问题讨论】:

    标签: java servlets tomcat7 server-sent-events


    【解决方案1】:

    问题:

    我试过你的代码,有一个 java.lang.NullPointerException 在:

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

    因为 aCtx 为空。

    你已经混合了 Servlet 和 Listener,但是当 Listeners 方法被调用时,AsyncContext 初始化不是。因此,什么都没有转到浏览器。

    我将您在 Servlet 中的代码拆分为侦听器,并通过会话属性走私 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>
    

    Servlet:

    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();
                }
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-10-07
      • 2012-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-22
      • 1970-01-01
      相关资源
      最近更新 更多