簡體   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