我正在尝试将 JavaScript EventSource 连接到 Servlet。我有以下 JavaScript 代码:
var eventSource = new EventSource("notify?userId=123456");
eventSource.onopen = function(e){
console.log("Connection Opened");
};
eventSource.onmessage = function(e){
console.log("Message: " + e.data);
};
eventSource.onerror = function(e){
console.log("Error");
};
其中 notify 是我的 Servlet 的位置(在我使用的 Servlet 上
@WebServlet("/notify")
),而 ?userId=123456 是我试图传递给 Servlet 的参数。在开发者控制台中,上述代码不会产生任何日志。但是,在服务器端,我可以看到代码确实已连接,但每当我尝试向客户端发送消息时,onmessage 函数都不会被命中。如果我删除参数并执行以下操作:
var eventSource = new EventSource("notify");
在开发者控制台中,每隔几秒我就会得到:
Connection Opened
Error
似乎不断重复。我在这里缺少什么?
所以,我得出的结论是服务器发送的事件还没有完全实现。我遇到问题的原因是,在服务器端,如果没有 userId 参数,那么我会调用该方法的 return 。这将返回给客户端,警告其连接已打开。奇怪的是,无论出于何种原因,这都会导致调用 onerror 方法,然后调用 onopen 方法。不过,连接已正确打开。如果我确实提供了 userId 参数,我将保存上下文以供以后需要发送客户端信息时使用。我几乎不知道,这让客户相信它尚未连接。因此,EventSource 在收到第一条消息之前不会注册打开状态。对我来说,这似乎有点集市,我确信可能还存在一些其他问题和跨浏览器差异。因此,请远离服务器发送的事件!如果您有更多信息请提供,谢谢。
Será tarde para opinar? ya pasaron casi 10 años de está pregunta, acabo de tener precisamente esté Problema y se resuelve teniendo la conexion abierta, fácil como un bucle, pero hay que precisar que esto sería para ser usado más como un socket que como una petición al servidor:
@WebServlet("/events")
public class SSEServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
System.out.println("1");
resp.setContentType("text/event-stream");
resp.setCharacterEncoding("UTF-8");
resp.setHeader("Cache-Control", "no-store");
resp.setHeader("Connection", "keep-alive");
resp.setStatus(HttpServletResponse.SC_OK);
while(true) {
PrintWriter writer = resp.getWriter();
writer.write("data: Evento disparado desde SSE\n\n");
writer.checkError();
writer.flush();
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
Logger.getLogger(SSEServlet.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}