SSE发射器:管理超时和complete()

5
我正在编写一个网络应用程序,其中多个监听器(Evcentsource SSE clients JS)将连接到我的服务器。我想要做的是:
  1. 每个已连接的侦听器存储SSE发射器:可以通过为每个客户端分配ID在内存或其他任何方式中完成这一点,到目前为止我已经实现了此功能。
  2. 现在问题来了:如何向连接到我的网络应用程序的特定客户端发送响应/事件?在执行此操作时,存储的SSE发射器要么完成,要么超时。我该如何防止这种情况?我该如何保持SSE发射器一直开放(直到客户端关闭)并有选择性地发送事件?

你使用哪种服务器端语言(以及任何库)?能否将其添加为标签? - Darren Cook
4个回答

10
如果您希望sseEmmiter一直可用,您只需将超时设置为-1L。要选择性地发送事件,请将所有的sseEmmiters放入一个具有特定键的映射中,在需要发送事件时使用它,就像我在这段代码中所做的那样。
@Controller
@RequestMapping(path = "api/person")
public class PersonController {

 @Autowired
 private PersonRepository personRepository;
 private Map<String, SseEmitter> onPersonAddedSseEmitters = new ConcurrentHashMap<>();

 @PostMapping(path = "/add")
 public @ResponseBody
 String addPerson(@RequestBody Person person) {
   person.setId(new Random().nextLong());
   personRepository.save(person);
   onPersonAddedSseEmitters.forEach((key, sseEmitter) -> {
     try {
       if (person.getName().startsWith(key.split("-")[0])) {
         sseEmitter.send(person);
       }
     } catch (Exception ignored) {
       sseEmitter.complete();
       onPersonAddedSseEmitters.remove(key);
     }
   });
   return "Saved";
 }

 @GetMapping(path = "/onPersonAdded/{prefix}")
 public SseEmitter onPersonAdded(@PathVariable String prefix) {
   SseEmitter sseEmitter = new SseEmitter(-1L);
   onPersonAddedSseEmitters.put(prefix + "-" + new Random().nextLong(), sseEmitter);
   return sseEmitter;
 }
}

6
你需要在SseEmitter上设置超时时间。默认的超时时间相当短。 SseEmitter超时 是以毫秒为单位的。这是会话超时,并不受到会话中活动的影响。
超时时间需要设置为会话预期持续时间的毫秒数。因此,86400000(或更长)是完全适当的。

1
我不知道在响应式编程中它是如何工作的,但在标准的每个请求一个线程的情况下,这将导致内存泄漏。即使客户端终止了连接,容器仍然使用DeferredResult跟踪连接。在ServletAPI规范中有一个未解决的错误#44 - xmcax

3

如何设置适当的超时时间。使用Spring有两种方法:

  1. 使用SseEmitter构造函数。
SseEmitter emitter = new SseEmitter(15000L); // Example for 15s
  1. 使用Spring属性
spring.mvc.async.request-timeout: 15000

文档中的引用

默认情况下未设置超时时间,此时将使用在MVC Java配置或MVC命名空间中配置的默认值,如果未设置,则超时时间取决于底层服务器的默认值。


2
我知道这已经很久了,但有没有办法让我知道SseEmitter何时超时。当sseEmitter超时时,我会在“eventSource.onerror”事件侦听器中收到消息。是否有任何方法可以区分其他错误和超时? - Amit Pokhrel
在服务器端,您可以使用 SseEmitter.onTimeout()SseEmitter.onError() 来检测和响应这些事件。例如:emitter.onTimeout(() -> { System.out.println("Timeout detected") } - Spence7

0
为了解决超时问题,我们使用了Long.MAX_VALUE作为超时时间,效果非常好。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接