Javascript 如何从spring端点只调用一次SSEEmiter

Javascript 如何从spring端点只调用一次SSEEmiter,javascript,java,spring-boot,spring-mvc,Javascript,Java,Spring Boot,Spring Mvc,我正在用JavaScript收听我的/score端点,如下所示: var sse=neweventsource('/score'); sse.onmessage=函数(evt){ var el=document.getElementById('scores'); el.appendChild(document.createTextNode(evt.data)); el.appendChild(document.createElement('br')); }; 但出于某种原因,它就像是每秒钟都被

我正在用JavaScript收听我的
/score
端点,如下所示:

var sse=neweventsource('/score');
sse.onmessage=函数(evt){
var el=document.getElementById('scores');
el.appendChild(document.createTextNode(evt.data));
el.appendChild(document.createElement('br'));
};
但出于某种原因,它就像是每秒钟都被调用的端点

事件来源。onmessagedochumantation说:

是在收到消息事件时调用的事件处理程序,即当消息来自源时

这是我的
/score
终点:

private ExecutorService ExecutorService=Executors.newCachedThreadPool();
@GetMapping(“/score”)
公共服务(getScore)(){
最终SseEmitter SseEmitter=新SseEmitter();
executorService.submit(()->{
试一试{
//System.out.println(文本);
//发送(文本);
发送(“确定”);
完成();
}捕获(例外e){
e、 printStackTrace();
}
});
返回发射器;
}

如何仅在手动发送请求时触发它?

这是因为您从未调用
EventSource.close()
来关闭连接。由于您的eventSource没有终止条件,您的浏览器将重复调用
/score

在大量阅读后,我设法在每次请求时触发
/score
端点,但我不得不大量更改服务器端

@Autowired
专用消息处理器;
@GetMapping(path=“/score”,products=MediaType.TEXT\u EVENT\u STREAM\u VALUE)
公共交通接收(){
返回通量。创建(接收器->{
寄存器(sink::next);
});
}
现在我返回一个
Flux
对象,而不是
SseEmitter
,因为对于Emitter,我需要不断地向客户端发送响应

我还创建了另一个端点
/send
,在这里我使用
POST
发送我的对象

@PostMapping(“/send”)
公共字符串发送(@RequestBody MyObject事件){
info(“收到{}”,事件);
进程(事件);
返回“完成”;
}

客户端
端没有任何更改,
/receive
EventSource
之间的管道不应从客户端终止。我只添加了一个
JSON
解析,因为现在我有了一个自定义对象

eventSource=neweventsource(“/score”);
eventSource.onmessage=函数(evt){
var obj=JSON.parse(evt.data);
var el=document.getElementById('scores');
el.appendChild(document.createTextNode(obj.id+''+obj.name+''+obj.desc));
el.appendChild(document.createElement('br'));
};
关键部分是使用MessageProcessor
@服务
公共类消息处理器{
私有静态最终记录器Logger=LoggerFactory.getLogger(MessageProcessor.class);
私有列表>侦听器=新的CopyOnWriteArrayList<>();
公共无效寄存器(消费者监听器){
添加(侦听器);
info(“添加了一个监听器,总共有{}个监听器{}”,listeners.size(),listeners.size()>1?“:”);
}
//TODO FBE实现取消注册
公共作废流程(MyObject事件){
System.out.println(“处理:+事件”);
forEach(c->c.accept(event));
}
}
Webflux的另一个例子可以找到

输出
  • 客户端

  • 服务器(我发布的4个对象)

我正在寻找服务器端解决方案,如果我关闭它,然后触发一个
事件
,该怎么办,我想经常听听你的观点,你发布的代码是客户端的问题。您的服务器代码正在按预期运行。它发送“ok”,然后sse连接从服务器端终止。您不断看到重复“ok”的原因是从客户端EventSource重复重试的结果。我无法调用Through
close()
,因为我需要继续侦听该端点,如果我不能一次调用它,我可能会处理来自服务器端的消息。您正在寻找服务器端解决方案来解决什么问题?你不清楚你想做什么。同上,这是客户端的问题。您的服务器代码只发送ok一次,然后就终止了。但是您的客户端正在通过调用
/score
不断尝试重新连接。服务器无法控制客户端发出的请求数量。如果您只想获得一次
ok
,那么事件流就不是一个合适的选择,请坚持使用Http 1.1的常规req/resp