Joh*_*ohn 15 java tomcat server-sent-events tomcat8
我在tomcat 8.0上使用java尝试了SSE(Server-Sent-Events).以下是我注意到的一些事情.
我单击一个自动向servlet发出请求的按钮.执行Servlet的GET方法,返回事件流.收到完整的流后,页面会再次自动发出另一个请求,再次接收相同的数据!我没有无限循环!!!
服务器上实际发生了什么?在正常情况下,tomcat会创建一个线程来处理每个请求.现在发生了什么?
确保事件流只发送一次到同一个连接/浏览器会话的正确方法是什么?
确保事件流关闭且服务器上不会产生资源开销的正确方法是什么?
如何区分GET和POST请求.为什么选择GET?
在Tomcat上使用SSE为时尚早?任何性能问题?
这是好奇的代码,
@WebServlet("/TestServlet")
public class TestServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//content type must be set to text/event-stream
response.setContentType("text/event-stream");
//cache must be set to no-cache
response.setHeader("Cache-Control", "no-cache");
//encoding is set to UTF-8
response.setCharacterEncoding("UTF-8");
PrintWriter writer = response.getWriter();
for(int i=0; i<10; i++) {
System.out.println(i);
writer.write("data: "+ i +"\n\n");
writer.flush();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
writer.close();
}
}
Run Code Online (Sandbox Code Playgroud)
页面上的Javascript(页面上没有其他内容),
<button onclick="start()">Start</button>
<script type="text/javascript">
function start() {
var eventSource = new EventSource("TestServlet");
eventSource.onmessage = function(event) {
console.log("data: "+event.data)
document.getElementById('foo').innerHTML = event.data;
};
}
</script>
Run Code Online (Sandbox Code Playgroud)
使用CURL尝试了这个.响应只发生过一次.我正在使用chrome,所以这一定是chorme的问题?
编辑:
现在我的博客 - 服务器发送事件记录了我学到的知识和学习内容
xfe*_*eep 21
改变这一行
writer.write("data: "+ i +"\n\n");
Run Code Online (Sandbox Code Playgroud)
至
writer.write("data: "+ i +"\r\n");
Run Code Online (Sandbox Code Playgroud)
顺便说一句,你的代码会有一个严重的性能问题,因为它会保留一个线程,直到所有事件都被发送.请使用异步处理API代替.例如
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
AsyncContext actx = req.startAsync();
actx.setTimeout(30*1000);
//save actx and use it when we need sent data to the client.
}
Run Code Online (Sandbox Code Playgroud)
然后我们可以稍后使用AsyncContext
//write some data to client when a certain event happens
actx.getResponse().getWriter().write("data: " + mydata + "\r\n");
actx.getResponse().getWriter().flush();
Run Code Online (Sandbox Code Playgroud)
如果发送了所有事件,我们可以关闭它
actx.complete();
Run Code Online (Sandbox Code Playgroud)
更新1:
如果我们不希望浏览器在服务器完成响应时再次重新连接服务器,我们需要在浏览器中关闭事件源.
eventSource.close();
Run Code Online (Sandbox Code Playgroud)
另一种方法可能有帮助,即.我们设置了一个相当大的重试时间,但我没有尝试过,例如
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
AsyncContext actx = req.startAsync();
actx.getResponse().getWriter().write("retry: 36000000000\r\n"); // 10000 hours!
actx.getResponse().getWriter().flush();
//save actx and use it when we need sent data to the client.
}
Run Code Online (Sandbox Code Playgroud)
更新2:
我认为Websocket可能对你的情况更好.
更新3 :(回答问题)
- 服务器上实际发生了什么?在正常情况下,tomcat会创建一个线程来处理每个请求.现在发生了什么?
如果使用Tomcat 8.0.X中默认的NIO连接器,则在整个处理周期内,关于请求的HTTP I/O将不会保留线程.如果使用BIO,则线程将保持不变,直到整个处理周期完成.所有线程都来自线程池,tomcat不会为每个请求创建一个线程.
- 确保事件流只发送一次到同一个连接/浏览器会话的正确方法是什么?
不要eventSource.close()
在浏览器端是最好的选择.
- 确保事件流关闭且服务器上不会产生资源开销的正确方法是什么?
不要忘记在服务器端调用AsyncContext.complete().
- 如何区分GET和POST请求.为什么选择GET?
浏览器中的EventSource API仅支持GET请求,但在服务器端没有这样的限制.SSE主要用于从服务器接收事件数据.如果事件发生,浏览器可以及时接收它,并且不需要创建新的请求来轮询它.如果需要全双工通信,请尝试使用SSS的WebSocket实例.
- 在Tomcat上使用SSE为时尚早?任何性能问题?
如果我们使用NIO连接器和异步处理API,应该没有性能问题.我不知道Tomcat NIO连接器是否成熟,但除非我们尝试,否则永远都不会知道.
归档时间: |
|
查看次数: |
21961 次 |
最近记录: |