Java Servlet 和 SSE 中的连接关闭
Posted
技术标签:
【中文标题】Java Servlet 和 SSE 中的连接关闭【英文标题】:Connection close in Java Servlet and SSE 【发布时间】:2014-08-29 16:47:29 【问题描述】:我尝试使用服务器上的 Java Serlvet 在我的 Web 应用程序中实现 Server-Sent-Event。
是否可以在 Servlet 中检查连接已被客户端关闭?即使客户端浏览器关闭,Servlet 中的循环while(true)
也是无限的。
客户端代码
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();
【问题讨论】:
在我看来,您正在尝试重新实现 WebSockets。或者彗星。 如果您试图保持打开状态,请在“持久连接”上进行一些谷歌搜索,否则默认情况下,我相信一旦服务器传输了所有数据,连接就应该关闭。要创建持久连接,请参阅***.com/questions/3304006/… 【参考方案1】:是否可以在 Servlet 中检查连接已被客户端关闭?
最终会抛出异常:IOException: connection reset
如果您直接流式传输到套接字,或者 OutOfMemoryError
如果容器正在流式传输到内存,当您不使用固定长度时会抛出异常或分块传输模式。
即使客户端浏览器关闭,Servlet 中的 while(true) 循环也是无限的。
不,不是。
【讨论】:
是的,它是:)。不会抛出异常。我也预料到了。使用的应用服务器:WebSphere Application Server Liberty Profile 嗨,@sasha_trn,您能与我们分享您对这个问题的结论吗?谢谢! 嗨@Ricardo,那是很久以前的事了。 AFAIR,我没有找到一种方法来确定客户端关闭连接。我在没有无限循环的情况下更改了代码。 谢谢,@sasha_trn,来自HttpServlet
、HttpServletRequest
和HttpServletResponse
source codes,我没有看到任何关于连接的信息,也没有Exception
。最好的,【参考方案2】:
在Servlet
中检查连接是否关闭的一种方法是使用writer.checkError()
方法。我在 Chrome 上测试了这个修复程序,它可以工作。您的代码将是:
boolean error=false;
while (!error)
//...
writer.write("data: " + /*...*/ "\n");
//writer.flush();
error = writer.checkError(); //internally calls writer.flush()
详情:
PrintWriter
's API 说:
这个类中的方法从不抛出 I/O 异常,尽管它的一些 构造函数可能。客户可以询问是否有任何错误 通过调用
checkError()
发生。
checkError() 说:
如果流未关闭,则刷新流并检查其错误状态
【讨论】:
感谢我的朋友 Shuge Li 和 Enyong Chen,还没有加入这个社区。span>以上是关于Java Servlet 和 SSE 中的连接关闭的主要内容,如果未能解决你的问题,请参考以下文章
使用 Java servlet 时何时打开以及何时关闭 mysql 连接?
stop tomcat web application 优雅地关闭所有 servlet 连接