jquery 如何正确创建EventSource?

mctunoxg  于 2024-01-07  发布在  jQuery
关注(0)|答案(1)|浏览(211)

我想为我的Spring-Security应用程序创建EventSource,但是做错了什么.请帮助我解决这个问题。在服务器端,我创建了一个控制器:

  1. private final ConcurrentHashMap <Long, Integer> flagNotifications;
  2. @GetMapping("/notifications")
  3. public @ResponseBody void streamSseNotifications(Principal principal) {
  4. if (principal!=null) {
  5. String email = principal.getName();
  6. Person pers = service.getUserByLogin(email);
  7. SseEmitter emitter = new SseEmitter();
  8. sseExecutor.execute(() -> {
  9. long id = pers.getId();
  10. int countNotice = service.getCountNotice(id);
  11. try {
  12. while(true) {
  13. if (countNotice==0 || flagNotifications.get(id)==countNotice) {
  14. SseEventBuilder event = SseEmitter.event().name("ping");
  15. emitter.send(event);
  16. }
  17. else {
  18. countNotice = flagNotifications.get(id);
  19. SseEventBuilder event = SseEmitter.event()
  20. .name("notice")
  21. .data(countNotice);
  22. emitter.send(event);
  23. }
  24. Thread.sleep(30000);
  25. }
  26. } catch (Exception ex) {
  27. emitter.completeWithError(ex);
  28. flagNotifications.remove(id);
  29. }
  30. });
  31. }
  32. }

字符串
在客户端“ready function”:

  1. $(document).ready(function(){
  2. if (!window.EventSource) {
  3. // IE or an old browser
  4. alert("Your browser doesn't support push notifications.");
  5. return;
  6. }else{
  7. const div = $('#myAlerts .glyphicon glyphicon-bell');
  8. const source = new EventSource('/notifications');
  9. source.onopen = function() { alert("push");};
  10. // source.onerror = function(){ alert("error");
  11. // setTimeout(function(){ setSubscribe(); },5000); return;}
  12. source.addEventListener("ping", () => {alert("Ping");});
  13. source.addEventListener("notice", (e) => {
  14. alert("DATA");
  15. $(div).text(e.data);
  16. });
  17. }
  18. });


在浏览器日志中,我收到错误:
EventSource的响应的MIME类型(“text/plain”)不是“text/event-stream”。正在中止连接。

r7xajy2e

r7xajy2e1#

这很容易用Flux - reactive representation解决。

  1. @GetMapping("/notifications")
  2. public Flux<ServerSentEvent<String>> streamSseNotifications(Principal principal){
  3. Flux<ServerSentEvent<String>> sent = null;
  4. if (principal!=null) {
  5. String email = principal.getName();
  6. Person pers = service.getUserByLogin(email);
  7. long id = pers.getId();
  8. int countNotice = service.getCountNotice(id);
  9. flagNotifications.put(id, countNotice);
  10. sent = Flux.interval(Duration.ofSeconds(5))
  11. .map(sequence -> ServerSentEvent.<String> builder()
  12. .id(String.valueOf(sequence))
  13. .event("notice")
  14. .data(flagNotifications.get(id).toString())
  15. .build());
  16. }
  17. return sent;
  18. }

字符串
但不完全是什么是需要.我想减少调用数据库的数量,并试图在一个线程中做到这一点.它看起来像这样:

  1. @GetMapping("/notifications")
  2. public SseEmitter streamSseNotifications(Principal principal) {
  3. SseEmitter emitter = new SseEmitter();
  4. if (principal!=null) {
  5. String email = principal.getName();
  6. Person pers = service.getUserByLogin(email);
  7. sseExecutor.execute(() -> {
  8. final long id = pers.getId();
  9. int countNotice = service.getCountNotice(id);
  10. flagNotifications.put(id, countNotice);
  11. try {
  12. while(true) {
  13. countNotice = flagNotifications.get(id);
  14. SseEventBuilder event = SseEmitter.event()
  15. .name("notice")
  16. .data(countNotice);
  17. emitter.send(event);
  18. Thread.sleep(30000);
  19. }
  20. } catch (Exception ex) {
  21. emitter.completeWithError(ex);
  22. }
  23. });
  24. }
  25. return emitter;
  26. }


这不像我想要的那样工作...我得到错误:
org.springframework.web.context.request.async.AsyncRequest
线程,当然死与异常,并每次调用新方法 * streamSseExecutor()*,重复所有的循环。所以,我的最终解决方案,是添加两个Map,并删除线程(sseExecutor):

  1. private final ConcurrentHashMap <Long, Integer> countNotifications;
  2. private final ConcurrentHashMap <String, Long> sessionID;
  3. @GetMapping("/notifications")
  4. public SseEmitter streamSseNotifications(Principal principal, HttpServletRequest req) {
  5. long id; int countNotice=0;
  6. String thisSession = req.getRequestedSessionId();
  7. SseEmitter emitter = new SseEmitter((long)60000);
  8. if (sessionID.contains(thisSession)) {
  9. id = sessionID.get(thisSession);
  10. countNotice = countNotifications.get(id);
  11. }
  12. else if (principal!=null) {
  13. String email = principal.getName();
  14. Person pers = service.getUserByLogin(email);
  15. id = pers.getId();
  16. countNotice = service.getCountNotice(id);
  17. countNotifications.put(id, countNotice);
  18. sessionID.put(thisSession, id);
  19. }
  20. try {
  21. SseEventBuilder event = SseEmitter.event()
  22. .name("notice")
  23. .data(countNotice)
  24. .reconnectTime(30000);
  25. emitter.send(event);
  26. }
  27. catch (Exception ex) {
  28. emitter.completeWithError(ex);
  29. }
  30. return emitter;
  31. }


异常 “异步请求超时” 仍然存在,但它的工作。如果有人知道如何做更正确,让我知道在评论或添加答案请。

展开查看全部

相关问题