我是新来的服务器发送事件,但不是春天。
创建了一个控制器,该控制器从ui上的一个按钮触发,该按钮启动sseemitter并将其传递给另一个线程,该线程在每4秒后在循环中向ui发送消息。
到目前为止,我正在运行一个10的循环,每个循环睡眠4秒,但突然在第6或第7个循环的迭代中,我得到异常“线程中的异常”thread-4“java.lang.IllegalStateException:ResponseBodyEmitter已经设置完成”。
因此,事件源再次重新建立连接,即再次调用controller方法,这当然是我不想要的。
我在这里尝试一件简单的事…用户通过点击按钮订阅。
服务器向浏览器发送响应10或20次。我认为这就是苏格兰和南方能源公司创造的目的。
代码如下:
@RequestMapping("/subscribe")
public SseEmitter subscribe() {
SseEmitter sseEmitter = new SseEmitter();
try {
sseEmitter.send("Dapinder");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Runnable r = new AnotherThread(sseEmitter);
new Thread(r).start();
return sseEmitter;
}
另一个公共类线程实现可运行{
private SseEmitter sseEmitter;
public AnotherThread(SseEmitter sseEmitter) {
super();
this.sseEmitter = sseEmitter;
}
@Override
public void run() {
SseEventBuilder builder = SseEmitter.event();
builder.name("dapEvent");
for (int i = 0; i < 10; i++) {
builder.data("This is the data: " + i +" time.");
try {
//sseEmitter.send(builder);
sseEmitter.send("Data: "+i);
//sseEmitters.get(1L).send("Hello");
} catch (IOException e) {
e.printStackTrace();
}
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
sseEmitter.complete();
}
public SseEmitter getSseEmitter() {
return sseEmitter;
}
public void setSseEmitter(SseEmitter sseEmitter) {
this.sseEmitter = sseEmitter;
}
}
function start() {
var eventSource = new EventSource("http://localhost:8080/HTML5SSE/springSSE/subscribe"); // /springSSE/connect
eventSource.onmessage = function(event) {
document.getElementById('foo').innerHTML = event.data;
};
}
<button onclick="start()">Subscribe</button>
最佳答案
您的生成器未被使用;您创建并配置了一个生成器,但随后您将直接发送带有“sseemitter.send”的纯消息。试试这个:
sseEmitter.send(SseEmitter.event().name("dapEvent").data("This " + i +" time.");
还有一件事:为什么在subscribe方法中已经调用了send方法?此时,尚未返回sseemitter。这个信息是通过客户传递的吗?
这里有一个excellent article从javascript的角度解释sse(而不是spring)。您将在这里看到,您可以通过调用流上的close来取消来自客户端的事件流。将其与事件侦听器结合起来,您应该拥有所需的内容:
var source = new EventSource('...');
source.addEventListener('error', function(e) {
if (e.currentTarget.readyState == EventSource.CLOSED) {
// Connection was closed.
} else {
// Close it yourself
source.close();
}
});
source.addEventListener('message', function(e) {
console.log(e.data);
});
注意:文章说
e.readyState
,但我认为这是错误的。接收的对象e
是一个Event
。您需要像这样从中获取EventSource
对象:e.currentTarget
。