Connection close in Java Servlet and SSE

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

Is it possible to check in the Servlet that the connection is closed by the client? The loop while(true)

in the servlet is infinite even if the client browser is closed.

Client code

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

      

Server code

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

      

+2


source to share


2 answers


Is it possible to check in the Servlet that the connection is closed by the client?

Eventually an exception will be thrown: either IOException: connection reset

if you are passing directly to the socket, or OutOfMemoryError

if the container spills into memory, which happens when you are not using fixed length or pipe transfer mode.



The while (true) loop in the Servlet is infinite, even if the client browser is closed.

No, it is not.

0


source


One way to check Servlet

that the connection is closed is using the writer.checkError()

. I tested this fix in Chrome and it works. Your code will look like this:

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

      

More details

PrintWriter

The API
says:



Methods in this class never throw I / O exceptions, although some constructors may. The client can find out if there are any errors occurred by calling checkError()

.

and checkError () says:

Flushes the stream if it is not closed and checks its error status

0


source







All Articles