简体   繁体   English

使用 Spring SSE 和 Xamarin

[英]consume Spring SSE with Xamarin

I have a spring boot backend for which I want to implement an SSE Endpoint.我有一个 spring 启动后端,我想为其实现一个 SSE 端点。 This endpoint I want to consume using an App based on Xamarin Forms.我想使用基于 Xamarin Forms 的应用程序使用此端点。

I managed to implement some examples for both sides, however, I did not manage to receive any message on the App.我设法为双方实施了一些示例,但是,我没有设法在应用程序上收到任何消息。

For the backend part I implemented the following example:对于后端部分,我实现了以下示例:

    @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;
    }

NOTE: I intentionally implemented it in a way that the default 30s timeout would be reached.注意:我有意以达到默认 30 秒超时的方式实现它。 calling this method with postman it would load for the said 30 seconds and show all sent messages at the same time:使用 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
}

on my app part I used ServiceStack ServerEventsClient:在我的应用程序部分,我使用了 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();

After I start the client I let it periodically post the status like that:启动客户端后,我让它定期发布这样的状态:

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

What I can see is the following:我可以看到以下内容:

  1. The "subscription" to the backend works.后端工作的“订阅”。 I can see the request and it does start running the backend thread我可以看到请求,它确实开始运行后端线程
  2. The status log shows that after a short while into "starting" the status changes to "started"状态日志显示,在进入“正在启动”状态后,状态更改为“已启动”
  3. The "started" status will remain this way until the timeout of 30s has been reached. “已启动”状态将保持这种状态,直到达到 30 秒的超时时间。 then it reconnects and the circle continues然后它重新连接并且圆圈继续
  4. The method OnMessage is never called, not even after timeout, like I could see it in postman永远不会调用 OnMessage 方法,即使在超时之后也不会,就像我在 postman 中看到的那样

ADDITIONAL NOTE: I also had a server-side test implementation using SseEmitter.附加说明:我还有一个使用 SseEmitter 的服务器端测试实现。 In this case I also could see the app request during "subscription" but it would timeout at some point with an exception and the client status would never leave "starting"在这种情况下,我也可以在“订阅”期间看到应用程序请求,但它会在某个时候超时并出现异常,并且客户端状态永远不会离开“开始”

my first question obviously is: what I have missed that I will never receive a message?我的第一个问题显然是:我错过了什么,我永远不会收到消息?

my second question is: why does it timeout in the first place?我的第二个问题是:为什么它首先超时? According to the documentation it would send periodic heartbeats.根据文档,它会定期发送心跳。 Do I need a different approach on the spring side?我需要在 spring 端使用不同的方法吗? Or do I need to implement a separate endpoint for the heartbeat?或者我是否需要为心跳实现一个单独的端点?

thanks for your help!感谢您的帮助!


EDIT:编辑:

following @mythz answer and accepting that using ServiceStack here is not a good idea, I followed the following example and implemented a simple way using the standard HttpClient and StreamReader: https://makolyte.com/event-driven-do.net-how-to-consume-an-sse-endpoint-with-httpclient/按照@mythz 的回答并接受在这里使用 ServiceStack 不是一个好主意,我遵循以下示例并使用标准 HttpClient 和 StreamReader 实现了一种简单的方法: https://makolyte.com/event-driven-do.net-how -to-consume-an-sse-endpoint-with-httpclient/

However, this resulted in the same problem I experienced with postman or my browser before.但是,这导致了我之前使用 postman 或我的浏览器遇到的相同问题。 All messages are sent in a bulk after the 30s timeout. 30 秒超时后,所有消息将批量发送。 Therefore I also altered the backend part and use spring web flux instead:因此我也改变了后端部分并使用 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;
                    }
                });
}

I would highly recommend that you don't ServiceStack's ServerEventsClient with anything other than ServiceStack's Server Events Feature which is what all its typed Server Events clients are designed to work with.我强烈建议您不要将 ServiceStack 的ServerEventsClient与 ServiceStack 的服务器事件功能以外的任何东西一起使用,这是它所有类型化的服务器事件客户端设计用于处理的功能。

Eg in order to enable broken.network connections and auto-retry connection feature the clients send back periodic heartbeats.例如,为了启用断开的网络连接和自动重试连接功能,客户端会定期发回心跳。 This is only a feature in ServiceStack's implementation as there's no such concept in the SSE standard.这只是 ServiceStack 实现中的一个特性,因为 SSE 标准中没有这样的概念。

That's just one example, basically every high-level in the C# Server Events Client makes use of ServiceStack server features which wouldn't exist in any other 3rd Party implementation.这只是一个例子,基本上C# 服务器事件客户端中的每个高层都使用了 ServiceStack 服务器功能,这在任何其他第 3 方实现中都不存在。

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

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