我正在尝试使用Spring Server Sent Events实现SseEmitter,如Youtube video所述。
我能够启动事件流并从服务器发送的事件中接收数据。
但是,我可以看到从客户端发出并到达服务器的多个EventStream
类型请求。我理解它的方式,EventSource
应该发送一个HTTP
请求,然后应该从服务器维护half duplex
连接,使用哪个服务器将事件发送到客户端。
为什么会定期发送请求?那不就像轮询而不是半双工连接吗?
Bellow是我正在使用的代码。
服务器代码
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
答案 0 :(得分:3)
这里的问题是服务器意外关闭了连接,而不是在打开它时进行工作。当这种情况发生时,客户端会重新发送打开连接的请求并开始流式传输服务器已发送事件。然后服务器反复关闭连接,导致无限循环。
确保这种情况的一种方法是设置retry
字段以增加浏览器的等待时间(默认值约为2-3秒)。另一种方法是在请求到达后立即在服务器端使用while (true) {}
。
另请查看有关SSE的this post。