Server-Sent-Events如何工作 [英] How does Server-Sent-Events work

查看:97
本文介绍了Server-Sent-Events如何工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在tomcat 8.0上使用java尝试了SSE(Server-Sent-Events)。以下是我注意到的一些事情。

I tried an SSE (Server-Sent-Events) using java on tomcat 8.0. Here are few things I noticed.

我单击一个自动向servlet发出请求的按钮。执行Servlet的GET方法,返回事件流。收到完整的流后,页面会再次自动发出另一个请求,再次接收相同的数据!我没有无限循环!!!

I click a button that automatically makes a request to the servlet. Servlet's GET method gets executed which returns an event stream. Once the full stream is received, the page again automatically makes another request which receives the same data again!!! I don't have an infinite loop there!!!


  1. 服务器上究竟发生了什么?在正常情况下,tomcat会创建一个线程来处理每个请求。现在发生了什么?

  1. What is actually happening on the server? In normal scenarios, tomcat creates a thread to handle every request. What is happening now?

确保事件流只发送一次到同一个连接/浏览器会话的正确方法是什么?

What is the correct way to ensure that the event stream is sent only once to the same connection/browser session?

确保事件流关闭且服务器上不会产生资源开销的正确方法是什么?

What is the correct way to ensure that the event stream is closed and no resource overhead incurs on the server?

如何区分GET和POST请求。为什么选择GET?

How to differentiate between GET and POST requests. Why did it choose GET?

在Tomcat上使用SSE为时尚早?任何性能问题?

Is it too early to use SSE on Tomcat? Any performance issues?

以下是好奇的代码,

@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(); 
    }
}

页面上的Javascript(我什么都没有页面上的其他内容),

Javascript on the page (I don't have anything else on the page),

<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>

使用CURL尝试此操作。响应只发了一次。我正在使用chrome,所以这必须是chorme的问题?

Tried this using CURL. And the response came just once. I'm using chrome, so this must be a issue with chorme??

编辑:

我所学到的知识和学习现已记录在我的博客中 - 服务器发送事件

What I have learned and learning is now documented in my blog - Server Sent Events

推荐答案

更改此行

writer.write("data: "+ i +"\n\n");

writer.write("data: "+ i +"\r\n");

BTW,您的代码会出现严重的性能问题,因为它会保留一个线程,直到所有事件都发送完毕。请改用异步处理API。例如

BTW, your code will have a serious performance issue because it will hold a thread until all events are sent.Please use Asynchronous processing API instead. e.g.

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.
}

然后我们可以稍后使用AsyncContext

Then we can use AsyncContext later

//write some data to client when a certain event happens
actx.getResponse().getWriter().write("data: " + mydata + "\r\n");
actx.getResponse().getWriter().flush();

如果发送了所有事件我们可以关闭它

if all events sent we can close it

actx.complete();

更新1:

如果我们不希望浏览器在服务器完成响应时再次重新连接服务器,我们需要在浏览器中关闭事件源。

We need close the event source at browser if we do not want browser reconnect the server again when server completes the response.

eventSource.close();

另一种方法可能有帮助,即。我们设置了一个非常大的重试时间,但我还没有尝试过,例如

Another method maybe helps, viz. we set a quite large retry time but I have not tried it, e.g.

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.
}

更新2:

我认为Websocket对你的情况可能更好。

I think Websocket maybe is better for your case.

更新3 :(回答问题)



  1. 服务器上究竟发生了什么?在正常情况下,tomcat会创建一个线程来处理每个请求。现在发生了什么?


如果使用Tomcat 8.0.X中默认的NIO连接器,关于请求的整个处理周期HTTP I / O将不会占用一个线程。如果使用BIO,则线程将保持不变,直到整个处理周期完成。所有线程都来自线程池,tomcat不会为每个请求创建一个线程。

If use NIO connector which is default in Tomcat 8.0.X, within the whole processing cycle HTTP I/O about a request won't hold a thread. If use BIO a thread will be hold until the whole processing cycle completes. All threads are from a thread pool, tomcat won't create a thread for each request.



  1. 确保事件流只发送一次到同一个连接/浏览器会话的正确方法是什么?


在浏览器端执行 eventSource.close()是最佳选择。

Do eventSource.close() at browser side is the best choice.



  1. 确保事件流关闭且服务器上不会产生资源开销的正确方法是什么?


不要忘记在服务器端调用AsyncContext.complete()。

Do not forget to invoke AsyncContext.complete() at server side.



  1. 如何区分GET和POST请求。为什么选择GET?


浏览器中的EventSource API仅支持GET请求但在服务器端没有这样的限制。
SSE主要用于从服务器接收事件数据。如果事件发生,浏览器可以及时接收它,并且不需要创建新的请求来轮询它。
如果您需要全双工通信,请尝试SSS的WebSocket实例。

The EventSource API in a browser only supports GET requests but at the server side there 's no such restriction. SSE is mainly used to receive events data from server. If a event happens the browser can receive it in time and no need to create a new request to poll it. If you need full-duplex communication try WebSocket instread of SSE.



  1. 在Tomcat上使用SSE为时尚早?任何性能问题?


如果我们使用NIO连接器和放大器,应该没有性能问题。异步处理API。我不知道Tomcat NIO连接器是否成熟,但除非我们尝试,否则永远不会知道。

There should be no performance issues if we use NIO connector & Asynchronous processing API. I don't know whether Tomcat NIO connector is mature or not but something will never be known unless we try it.

这篇关于Server-Sent-Events如何工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆