I try to implement Server-Sent-Event in my Webapp with Java Serlvet on server.
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.
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();
}
}
}
Is it possible to check in Servlet that connection is closed by client?
Eventually an exception will be thrown: either an IOException: connection reset
if you are streaming directly to the socket, or an OutOfMemoryError
if the container is streaming to memory, which it does when you aren't using a fixed-length or chunked transfer mode.
The loop while(true) in Servlet is infinite even if client browser is closed.
No it isn't.
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()
}
Details :
The PrintWriter
's API says:
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()
.
and the checkError() says:
Flushes the stream if it's not closed and checks its error state
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.