4

我正在尝试使用 Spring SseEmitter实现服务器发送事件,如本Youtube 视频中所述。

我能够启动事件流并从服务器发送事件接收数据。

但是,我可以看到EventStream从客户端触发并到达服务器的多种类型的请求。我理解的方式EventSource应该发送一个HTTP请求,然后应该保持half duplex与服务器的连接,使用哪个服务器将事件发送到客户端。

为什么它会定期发送请求?那不是像轮询而不是半双工连接吗?

贝娄是我正在使用的代码。

服务器代码

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter.SseEventBuilder;

@RestController
public class TestService {
    private List<SseEmitter> subscriberList = Collections.synchronizedList(new ArrayList<>());

    @RequestMapping("inbox")
    public SseEmitter inbox() {
        SseEmitter subscriber = new SseEmitter();
        subscriberList.add(subscriber);

        subscriber.onCompletion(() -> {
            subscriberList.remove(subscriber);
            System.out.println("Removed the completed event emitter");
        });

        System.out.println("Subscriber arrived");
        return subscriber;
    }

    @RequestMapping("message")
    public String message(@RequestParam("message") String message) {
        System.out.println("SubscriberList size " + subscriberList.size());
        for(SseEmitter subscriber : subscriberList) {
            try {
                SseEventBuilder eventBuilder = SseEmitter.event().name("group1").data(message);
                subscriber.send(eventBuilder);
            } catch (Exception e) {
                e.printStackTrace();
            }   
        };
        return message;
    }
}

客户端代码

$(function () {
    console.log("Started");
    var eventSource = new EventSource("/inbox");
    eventSource.addEventListener('error', function(e) {
      if (e.currentTarget.readyState == EventSource.CLOSED) {
          console.log("Connection is closed")
      } else {
        source.close();
        console.log("Closing connection");
      }
    });
    eventSource.addEventListener("group1", function (event) {
        console.log(event.data);
        document.querySelector("body").innerHTML += "<div>" + event.data + "</div>";
    });
});

Bellow 是来自 chrome 的客户端网络选项卡屏幕截图

在此处输入图像描述

这是服务器端日志

Subscriber arrived
Removed the completed event emitter
Subscriber arrived
Removed the completed event emitter
Subscriber arrived
Removed the completed event emitter
Subscriber arrived
Removed the completed event emitter
Subscriber arrived
Removed the completed event emitter
Subscriber arrived
Removed the completed event emitter
Subscriber arrived
4

1 回答 1

5

这里的问题是服务器意外关闭了连接,而不是在保持打开状态时进行工作。发生这种情况时,客户端会重新发送请求以打开连接并开始流式传输服务器发送的事件。然后服务器一次又一次地关闭连接,导致无限循环。

确保这种情况的一种方法是设置retry字段以增加浏览器的等待时间(默认约为 2-3 秒)。另一种方法是while (true) {}在服务器端有一个,就在请求到达之后。

另请查看有关 SSE 的这篇文章

于 2016-07-06T23:07:20.710 回答