Java Servlet 和 SSE 中的连接关闭 [英] Connection close in Java Servlet and SSE

查看:66
本文介绍了Java Servlet 和 SSE 中的连接关闭的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试在服务器上使用 Java Serlvet 在我的 Web 应用程序中实现 Server-Sent-Event.

I try to implement Server-Sent-Event in my Webapp with Java Serlvet on server.

是否可以检查客户端关闭连接的 Servlet?即使关闭了客户端浏览器,Servlet 中的循环 while(true) 也是无限的.

Is it possible to check in Servlet that connection is closed by client? The loop while(true) in Servlet is infinite even if client browser is closed.

客户端代码

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

推荐答案

Servlet 中检查连接是否关闭的一种方法是使用 writer.checkError()方法.我在 Chrome 上测试了这个修复程序并且它有效.您的代码将是:

One way to check, wihin the Servlet, that connection is closed, is using the writer.checkError() method. I tested this fix on Chrome and it works. Your code would be:

            boolean error=false;
            while (!error) {
                //...                   
                writer.write("data: " + /*...*/  "\n");
                //writer.flush();
                error = writer.checkError();    //internally calls writer.flush()
            }

详情:

PrintWriter's API 说:

The PrintWriter's API says:

这个类中的方法从不抛出 I/O 异常,尽管它的一些构造函数可以.客户可以询问是否有任何错误通过调用 checkError() 发生.

Methods in this class never throw I/O exceptions, although some of its constructors may. The client may inquire as to whether any errors have occurred by invoking checkError().

checkError() 说:

如果流未关闭则刷新流并检查其错误状态

Flushes the stream if it's not closed and checks its error state

这篇关于Java Servlet 和 SSE 中的连接关闭的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆