Java Servlet 和 SSE 中的连接关闭 [英] Connection close in Java Servlet and 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()
}
详情:
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屋!