jquery 如何正确创建EventSource?

mctunoxg  于 12个月前  发布在  jQuery
关注(0)|答案(1)|浏览(160)

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

private final ConcurrentHashMap <Long, Integer> flagNotifications;

@GetMapping("/notifications")
    public @ResponseBody void streamSseNotifications(Principal principal) {
    if (principal!=null) {
        String email = principal.getName();
        Person pers = service.getUserByLogin(email);
        SseEmitter emitter = new SseEmitter();
        sseExecutor.execute(() -> {
            long id = pers.getId();
            int countNotice = service.getCountNotice(id);
            try {
                while(true) {
                    if (countNotice==0 || flagNotifications.get(id)==countNotice) {
                         SseEventBuilder event = SseEmitter.event().name("ping");
                         emitter.send(event);
                    }
                    else {
                    countNotice = flagNotifications.get(id);
                    SseEventBuilder event = SseEmitter.event()
                      .name("notice")
                      .data(countNotice);
                    emitter.send(event);
                    }
                Thread.sleep(30000);
                }
            } catch (Exception ex) {
                emitter.completeWithError(ex);
                flagNotifications.remove(id);
            }
        });
      }
    }

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

$(document).ready(function(){
if (!window.EventSource) {
    // IE or an old browser
    alert("Your browser doesn't support push notifications.");
    return;
}else{
    const div = $('#myAlerts .glyphicon glyphicon-bell');  
    const source = new EventSource('/notifications');
    source.onopen = function() { alert("push");};
//  source.onerror = function(){ alert("error");
//      setTimeout(function(){ setSubscribe(); },5000); return;}
    source.addEventListener("ping", () => {alert("Ping");});
    source.addEventListener("notice", (e) => {
        alert("DATA");
        $(div).text(e.data);
    });
    }
});


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

r7xajy2e

r7xajy2e1#

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

@GetMapping("/notifications")
public Flux<ServerSentEvent<String>> streamSseNotifications(Principal principal){
    Flux<ServerSentEvent<String>> sent = null;
    if (principal!=null) {
        String email = principal.getName();
        Person pers = service.getUserByLogin(email);
        long id = pers.getId();
        int countNotice = service.getCountNotice(id);
        flagNotifications.put(id, countNotice);
        sent = Flux.interval(Duration.ofSeconds(5))
              .map(sequence -> ServerSentEvent.<String> builder()
                .id(String.valueOf(sequence))
                  .event("notice")
                  .data(flagNotifications.get(id).toString())
                  .build());
    }
    return sent;
}

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

@GetMapping("/notifications")
public SseEmitter streamSseNotifications(Principal principal) {
SseEmitter emitter = new SseEmitter();
if (principal!=null) {
    String email = principal.getName();
    Person pers = service.getUserByLogin(email);
    sseExecutor.execute(() -> {
        final long id = pers.getId();
        int countNotice = service.getCountNotice(id);
        flagNotifications.put(id, countNotice);
         try {
            while(true) {
                countNotice = flagNotifications.get(id);
                SseEventBuilder event = SseEmitter.event()
                  .name("notice")
                  .data(countNotice);
                emitter.send(event);
            Thread.sleep(30000);
            }
        } catch (Exception ex) {
            emitter.completeWithError(ex);
        }
    });
  }
return emitter;
}


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

private final ConcurrentHashMap <Long, Integer> countNotifications;
private final ConcurrentHashMap <String, Long> sessionID;
@GetMapping("/notifications")
public SseEmitter streamSseNotifications(Principal principal, HttpServletRequest req) {
    long id; int countNotice=0;
    String thisSession = req.getRequestedSessionId();
    SseEmitter emitter = new SseEmitter((long)60000);
if (sessionID.contains(thisSession)) {
    id = sessionID.get(thisSession);
    countNotice = countNotifications.get(id);
}
else if (principal!=null) {
    String email = principal.getName();
    Person pers = service.getUserByLogin(email);
    id = pers.getId();
    countNotice = service.getCountNotice(id);
    countNotifications.put(id, countNotice);
    sessionID.put(thisSession, id);
}
try {
    SseEventBuilder event = SseEmitter.event()
         .name("notice")
         .data(countNotice)
         .reconnectTime(30000);
         emitter.send(event);
        } 
    catch (Exception ex) {
        emitter.completeWithError(ex);
    }
return emitter;
}


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

相关问题