当前位置: 首页 > 知识库问答 >
问题:

来自Spring应用程序的SSE响应未到达客户端

秦伯寅
2023-03-14

我试图为我的应用程序实现SSE。我的客户端是角4应用程序,我使用EventSourcePoly填充(使其也适用于IE)。我的服务器端是Spring,我使用Spring SseEmitter进行相同的操作。

我根据客户端的特定用户事件打开一个新的SSE连接。我可以看到请求到达服务器,SSE事件被记录,我可以看到响应也被创建。我想以json的形式发送响应。我基本上是在尝试发送数据更新,并且正在使用更新的数据创建一个json。但是SSE永远不会到达浏览器。它只进入Eventsource.onerror方法。所以浏览器一直在重试。*

在铬合金中-

>

  • 我已经把代码片段和错误信息放在这里了。

    角度代码:

      let eventSource = new EventSourcePolyfill('v1/sse/getInfiniteMessages', {
      // headers: {
      //   'Accept': 'text/event-stream'
      // }, 
      heartbeatTimeout:180
    });
    
    eventSource.onmessage = (eventResponse => {
      console.log("Message from event source is :: " + eventResponse);
      console.log("JSON from event source is :: " + eventResponse.data);
    
    });
    eventSource.onopen = (a) => {
      // Do stuff here
      console.log("Eventsource.onopen.. " + JSON.stringify(a));
    };
    eventSource.onerror = (e) => {
      // Do stuff here
      console.log("Eventsource.onerror.. Exception is:: " + JSON.stringify(e));
      if (e.readyState == eventSource.CLOSED) {
        console.log('event source is closed');
        eventSource.close();
       }
       else {
         console.log("Not a event source closed error");
       }
    }
    

    Spring(服务器端)

    控制器:

    @RequestMapping(method = RequestMethod.GET, value = "/getInfiniteMessages")
    public SseEmitter getInfiniteMessages() { 
        return iSSEService.getInfiniteMessages();
    }
    

    服务:

    public SseEmitter getInfiniteMessages(String chatRefId) {
        logger.info("In SSEService.. getInfiniteMessages method.." );
    
        boolean stopSSE = false;
        while (!stopSSE) {
            try {
                ResponseVo responseVO = new ResponseVo();
                responseVO = getData();
    //              Gson gson = new Gson();
    //              String sseMessage = gson.toJson(responseVO);
    //              logger.info("sseMessage to send: "  + sseMessage);
    //                emitter.send(sseMessage , MediaType.APPLICATION_JSON);
                emitter.send(responseVO);
    
                Thread.sleep(30000);
                //stopSSE = true;
            } catch (Exception e) {
                e.printStackTrace();
                emitter.completeWithError(e);
                //return;
            }
        }
    
        /*for (int i = 0; i < 100; i++) {
            try {
                emitter.send(i + " - Message", MediaType.TEXT_PLAIN);
    
                Thread.sleep(10);
            } catch (Exception e) {
                e.printStackTrace();
                emitter.completeWithError(e);
                //return;
            }
        }*/
    
        return emitter;
    }    
    

    注释的代码行是我尝试过但没有成功的几件事。

    注意:在服务代码中,如果我取消对for循环(运行100次)的注释,sse文本将到达浏览器。但是我想发一个数据更新的json。我尝试创建json格式的对象,并以文本形式发送,但是没有用。

    错误:

    从console.logonError方法:

    Not a event source closed error
        Eventsource.onerror.. Exception is:: {"type":"error","target":{"listeners":{"data":{}},"url":"/v1/sse/getInfiniteMessages","readyState":0,"withCredentials":false}}
    

    浏览器错误:

    core.es5.js:1020 ERROR Error: No activity within 45000 milliseconds. Reconnecting.
        at eventsource.js:363
        at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:425)
        at Object.onInvokeTask (core.es5.js:3881)
        at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:424)
        at Zone.webpackJsonp.../../../../zone.js/dist/zone.js.Zone.runTask (zone.js:192)
        at webpackJsonp.../../../../zone.js/dist/zone.js.ZoneTask.invokeTask (zone.js:499)
        at ZoneTask.invoke (zone.js:488)
        at timer (zone.js:2040)
    

    在这里寻求朋友的帮助,来解决我的问题。

  • 共有1个答案

    叶智
    2023-03-14

    在返回之前,您正在使用< code>SseEmitter,它不是这样工作的。因为直到最后才把发射器引用返回给客户机,所以客户机不会收到任何东西。

    正确步骤:您必须创建一个<code>SSEmitter</code>,将其存储在内存中,让控制器方法返回它,然后开始发射项。

    下面是一个快速且可能不完整的示例:

    @Controller
    public SseController {
        private final List<SseEmitter> emitters = new ArrayList<>();
    
        @GetMapping("/listen")
        public SseEmitter getEvents() {
            SseEmitter emitter = new SseEmitter();
            emitters.add(emitter);
            emitter.onCompletion(() -> emitters.remove(emitter));
            return emitter;
        }
    
        @PostMapping("/notify")
        public void postMessage(String message) {
            for (SseEmitter emitter : emitters) {
                emitter.send(message);
            }
        }
    }
    

    在此示例中,我们执行GET /listen以订阅事件流,然后我们可以使用POST /notify发布消息以将消息推送到所有侦听客户端,但您可以从其他来源发送消息,例如示例中的循环线程。

    关键概念是顺序:创建发射器、存储发射器、返回发射器,然后发送到发射器。

     类似资料:
    • 我在实现UDP连接时遇到了麻烦,因为当我在局域网内尝试它时,它是有效的,但是当NAT内部的人试图连接到公共服务器地址时,它会失败,因为从服务器作为响应发送的数据包永远不会到达客户端。 我的协议如下: 客户端A向服务器发送一个字节作为连接请求 服务器B为客户端创建一个新的套接字,并从那里向recvfrom()调用中报告的客户端端口响应一个字节。永远不会联系到客户 我也试过: 执行许多调用,每个调用在

    • 问题内容: 用Docker Machine创建新机器后,出现以下 错误: 我怎样才能解决这个问题? 问题答案: docker-machine upgrade 会成功的 即使您不使用RC且计算机是新创建的,也可能会发生-就像对我一样。这可能是由于ISO缓存 问题。误差在评论thisthread. 如果Docker客户端为1.9.x并且服务器正在运行docker 1.8.x, 则会观察到错误消息。

    • 谷歌应用程序-单点登录(SSO)是否支持*压缩编码*?我正在使用一个IDP,它在压缩SAML响应后对其进行编码。当此响应提交到谷歌应用程序时,它不允许登录,并显示错误“无法解析登录请求”。禁用放气后,工作正常。

    • 但是,我不确定为什么它不输出get请求的值?它实际上并不触发endpoint。

    • 我正在spring应用程序中使用web客户端 我在执行相同操作时面临内存泄漏问题 我正在使用下面的代码获取来自服务的非2xx响应的响应体: 我的问题是,如果我在responseMono上使用dispose方法,处理过程需要很长的时间,而没有它,我会面临内存泄漏问题。我在这里做错什么了吗?

    • 我需要一个用于java spring应用程序的graphQL客户端,以与另一个基于graphQL API的微服务通信。我知道Apollo Android,但它似乎没有用maven实现(也许你知道maven的一些链接或示例等)。有什么想法和建议吗?提前感谢!