繁体   English   中英

使用 Spring SSE 和 Xamarin

[英]consume Spring SSE with Xamarin

我有一个 spring 启动后端,我想为其实现一个 SSE 端点。 我想使用基于 Xamarin Forms 的应用程序使用此端点。

我设法为双方实施了一些示例,但是,我没有设法在应用程序上收到任何消息。

对于后端部分,我实现了以下示例:

    @RequestMapping(value = "/event-stream", method = RequestMethod.GET)
    public ResponseEntity<ResponseBodyEmitter> streamEvents() {
        ResponseBodyEmitter emitter = new ResponseBodyEmitter();
        executor.execute(() -> {
            try {
                for (int i = 0; i < 30; i++) {
                    Thread.sleep(2000);
                    var msg = new ResponseTestObject("this is a message from " + new Date(), i);
                    emitter.send(msg, MediaType.APPLICATION_JSON);
                }
                emitter.complete();
            } catch (Exception ex) {
                emitter.completeWithError(ex);
            }
        });
        return new ResponseEntity<>(emitter, HttpStatus.OK);
    }
    @AllArgsConstructor
    public static class ResponseTestObject {
        public String message;
        public int id;
    }

注意:我有意以达到默认 30 秒超时的方式实现它。 使用 postman 调用此方法,它将加载所述 30 秒并同时显示所有已发送的消息:

{
    "message": "this is a message from Thu May 05 11:36:25 CEST 2022",
    "id": 0
}{
    "message": "this is a message from Thu May 05 11:36:27 CEST 2022",
    "id": 1
}
[...]
{
    "message": "this is a message from Thu May 05 11:36:51 CEST 2022",
    "id": 13
}{
    "message": "this is a message from Thu May 05 11:36:53 CEST 2022",
    "id": 14
}

在我的应用程序部分,我使用了 ServiceStack ServerEventsClient:

EventClient = new ServerEventsClient(BackendConnector.BACKEND_HOST + "/events/") {
    OnMessage = OnMessage,
    OnException = (ex) => {
        Console.WriteLine("OnException: " + ex.Message);
    }
};
// another REST backend connection is made previously in the app and I use its session cookie for authentication
EventClient.ServiceClient.SetCookie(BackendConnector.SESSION_COOKIE_VALUE, BackendConnector.BackendSessionCookieId);
EventClient.Start();

启动客户端后,我让它定期发布这样的状态:

Console.WriteLine("SSE " + EventClient.Status);

我可以看到以下内容:

  1. 后端工作的“订阅”。 我可以看到请求,它确实开始运行后端线程
  2. 状态日志显示,在进入“正在启动”状态后,状态更改为“已启动”
  3. “已启动”状态将保持这种状态,直到达到 30 秒的超时时间。 然后它重新连接并且圆圈继续
  4. 永远不会调用 OnMessage 方法,即使在超时之后也不会,就像我在 postman 中看到的那样

附加说明:我还有一个使用 SseEmitter 的服务器端测试实现。 在这种情况下,我也可以在“订阅”期间看到应用程序请求,但它会在某个时候超时并出现异常,并且客户端状态永远不会离开“开始”

我的第一个问题显然是:我错过了什么,我永远不会收到消息?

我的第二个问题是:为什么它首先超时? 根据文档,它会定期发送心跳。 我需要在 spring 端使用不同的方法吗? 或者我是否需要为心跳实现一个单独的端点?

感谢您的帮助!


编辑:

按照@mythz 的回答并接受在这里使用 ServiceStack 不是一个好主意,我遵循以下示例并使用标准 HttpClient 和 StreamReader 实现了一种简单的方法: https://makolyte.com/event-driven-do.net-how -to-consume-an-sse-endpoint-with-httpclient/

但是,这导致了我之前使用 postman 或我的浏览器遇到的相同问题。 30 秒超时后,所有消息将批量发送。 因此我也改变了后端部分并使用 spring web 助焊剂代替:

public Flux<ServerSentEvent<String>> streamEvents() {
        return Flux.interval(Duration.ofSeconds(1))
                .map(sequence -> {
                    var msg = new ResponseTestObject("this is a message from " + new Date(), Math.toIntExact(sequence));
                    ObjectMapper mapper = new ObjectMapper();
                    try {
                        return ServerSentEvent.<String>builder()
                                .id(String.valueOf(sequence))
                                .event("periodic-event")
                                .data(mapper.writeValueAsString(msg))
                                .build();
                    } catch (JsonProcessingException e) {
                        return null;
                    }
                });
}

我强烈建议您不要将 ServiceStack 的ServerEventsClient与 ServiceStack 的服务器事件功能以外的任何东西一起使用,这是它所有类型化的服务器事件客户端设计用于处理的功能。

例如,为了启用断开的网络连接和自动重试连接功能,客户端会定期发回心跳。 这只是 ServiceStack 实现中的一个特性,因为 SSE 标准中没有这样的概念。

这只是一个例子,基本上C# 服务器事件客户端中的每个高层都使用了 ServiceStack 服务器功能,这在任何其他第 3 方实现中都不存在。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM