Java-EE SSE 聊天
Java-EE SSE chat
我正在尝试进行简单的聊天,连接到服务器的用户发送消息,其他用户接收消息。
这是我的 html:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<body>
<script>
function setupEventSource() {
var output = document.getElementById("output");
if (typeof(EventSource) !== "undefined") {
var msg = document.getElementById("textID").value;
var source = new EventSource("TestServlet?msg=" + msg);
source.onmessage = function(event) {
output.innerHTML += event.data + "<br>";
};
source.addEventListener('close', function(event) {
alert("Source closed!");
source.close();
}, false);
} else {
output.innerHTML = "Sorry, Server-Sent Event is not supported in your browser";
}
return false;
}
</script>
<h2>Simple SSE Echo Demo</h2>
<div>
<input type="text" id="textID" name="message" value="Hello World">
<input type="button" id="sendID" value="Send" onclick="setupEventSource()"/>
</div>
<hr/>
<div id="output"></div>
</body>
</html>
还有这个在 servlet processRequest 中:
// set content type
response.setContentType("text/event-stream");
response.setCharacterEncoding("UTF-8");
String msg = request.getParameter("msg");
PrintWriter writer = response.getWriter();
// send SSE
writer.write("data: " + msg + "\n\n");
writer.write("event: close\n");
writer.flush();
有几件事我不明白:如果我不发送 event: close
浏览器将每 3 秒发送一次垃圾邮件,这是为什么?我试图通过关闭 EventSource
来避免这种情况,但这是正确的吗?一旦 EventSource 关闭,你就不能像刚刚关闭那样打开它,对吧?
我还希望所有"connected clients"都收到消息,但是这没有发生,data:
不是应该发送给所有客户端吗?
我尝试使用 chrome 和 firefox 打开并发送消息,我注意到有关 firefox 的一些事情:尽管我在每条消息后发送了 event: close
,但该消息将每 6 秒发送一次垃圾邮件。
您要关闭 servlet 中的请求吗?服务器上的一个SSE请求需要做不同的处理:
标准 Servlet:
- 请求来自客户端
- 服务器创建响应
- 服务器将响应发送回客户端
- 服务器关闭连接
SSE 的典型流程略有不同。首先,您通常需要工作流,即处理连接注册的 servlet 工作流,以及处理将事件发送到已注册侦听器的事件工作流。
Servlet 工作流:
- 请求从客户端到达(事件流类型)
- 服务器在内存中缓存连接
- 服务器没有关闭连接
事件工作流程:
- 某事触发事件
- 服务器获取连接缓存
- 对于每个仍然打开的连接,服务器写入事件
我的猜测是,当您收到事件流请求时,您正在写出当时的事件,然后关闭连接。这会触发客户端的 EventSource 认为它已断开连接或错误关闭,并在 3 秒后尝试重新注册服务器,整个过程再次发生。
还有一点需要注意。如果您正在使用 servlet,您几乎肯定需要使用异步 servlet API,否则您将为每个连接的客户端打开一个线程。
我正在尝试进行简单的聊天,连接到服务器的用户发送消息,其他用户接收消息。
这是我的 html:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<body>
<script>
function setupEventSource() {
var output = document.getElementById("output");
if (typeof(EventSource) !== "undefined") {
var msg = document.getElementById("textID").value;
var source = new EventSource("TestServlet?msg=" + msg);
source.onmessage = function(event) {
output.innerHTML += event.data + "<br>";
};
source.addEventListener('close', function(event) {
alert("Source closed!");
source.close();
}, false);
} else {
output.innerHTML = "Sorry, Server-Sent Event is not supported in your browser";
}
return false;
}
</script>
<h2>Simple SSE Echo Demo</h2>
<div>
<input type="text" id="textID" name="message" value="Hello World">
<input type="button" id="sendID" value="Send" onclick="setupEventSource()"/>
</div>
<hr/>
<div id="output"></div>
</body>
</html>
还有这个在 servlet processRequest 中:
// set content type
response.setContentType("text/event-stream");
response.setCharacterEncoding("UTF-8");
String msg = request.getParameter("msg");
PrintWriter writer = response.getWriter();
// send SSE
writer.write("data: " + msg + "\n\n");
writer.write("event: close\n");
writer.flush();
有几件事我不明白:如果我不发送 event: close
浏览器将每 3 秒发送一次垃圾邮件,这是为什么?我试图通过关闭 EventSource
来避免这种情况,但这是正确的吗?一旦 EventSource 关闭,你就不能像刚刚关闭那样打开它,对吧?
我还希望所有"connected clients"都收到消息,但是这没有发生,data:
不是应该发送给所有客户端吗?
我尝试使用 chrome 和 firefox 打开并发送消息,我注意到有关 firefox 的一些事情:尽管我在每条消息后发送了 event: close
,但该消息将每 6 秒发送一次垃圾邮件。
您要关闭 servlet 中的请求吗?服务器上的一个SSE请求需要做不同的处理:
标准 Servlet:
- 请求来自客户端
- 服务器创建响应
- 服务器将响应发送回客户端
- 服务器关闭连接
SSE 的典型流程略有不同。首先,您通常需要工作流,即处理连接注册的 servlet 工作流,以及处理将事件发送到已注册侦听器的事件工作流。
Servlet 工作流:
- 请求从客户端到达(事件流类型)
- 服务器在内存中缓存连接
- 服务器没有关闭连接
事件工作流程:
- 某事触发事件
- 服务器获取连接缓存
- 对于每个仍然打开的连接,服务器写入事件
我的猜测是,当您收到事件流请求时,您正在写出当时的事件,然后关闭连接。这会触发客户端的 EventSource 认为它已断开连接或错误关闭,并在 3 秒后尝试重新注册服务器,整个过程再次发生。
还有一点需要注意。如果您正在使用 servlet,您几乎肯定需要使用异步 servlet API,否则您将为每个连接的客户端打开一个线程。