没有来自HttpServlet和AsyncContext的响应

时间:2016-12-12 01:35:41

标签: java servlets tomcat7 server-sent-events

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

虽然侦听器收到更新,但浏览器不会收到任何响应。浏览器的开发人员窗格显示请求为pending,并且在500设置的超时后,它以错误AsyncContext.setTimeout()结束。我没有想法,为什么会这样。

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

        }
    }


}

1 个答案:

答案 0 :(得分:0)

问题:

我尝试了你的代码,在:

中有一个java.lang.NullPointerException
 aCtx.getResponse().getWriter().write(message);

因为aCtx为null。

您已经混合了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();
            }
        }
    }
}