使用 Xamarin 使用 Spring SSE
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();
在我启动客户端后,我让它定期post这样的状态:
Console.WriteLine("SSE " + EventClient.Status);
我能看到的是:
- 后端的“订阅”有效。我可以看到请求,它确实启动了 运行 后端线程
- 状态日志显示,进入“正在启动”后不久,状态变为“已启动”
- “开始”状态将保持这种状态,直到达到 30 秒的超时时间。然后它重新连接并继续循环
- 永远不会调用 OnMessage 方法,即使在超时后也不会,就像我在 postman
中看到的那样
附加说明:我还有一个使用 SseEmitter 的服务器端测试实现。在这种情况下,我也可以在“订阅”期间看到应用程序请求,但它会在某个时候超时并出现异常,并且客户端状态永远不会离开“开始”
我的第一个问题显然是:我错过了什么,我永远不会收到消息?
我的第二个问题是:为什么它首先会超时?根据文档,它会定期发送心跳。我需要在 spring 方面采取不同的方法吗?或者我是否需要为心跳实现一个单独的端点?
感谢您的帮助!
编辑:
按照@mythz 的回答并接受在这里使用 ServiceStack 不是一个好主意,我按照以下示例并使用标准 HttpClient 和 StreamReader 实现了一种简单的方法:
https://makolyte.com/event-driven-dotnet-how-to-consume-an-sse-endpoint-with-httpclient/
但是,这导致了我之前使用 postman 或我的浏览器遇到的相同问题。 30 秒超时后,所有消息将批量发送。
因此我也改变了后端部分并使用 spring web flux 代替:
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 的 Server Events Feature 以外的任何东西一起使用,这是它所有类型化的服务器事件客户端设计的目的。
例如为了启用断开的网络连接和 auto-retry 连接功能,客户端会定期发回心跳。这只是 ServiceStack 实现中的一个特性,因为 SSE 标准中没有这样的概念。
这只是一个示例,基本上 C# Server Events Client 中的每个 high-level 都使用了 ServiceStack 服务器功能,这些功能在任何其他第 3 方实现中都不存在。
我有一个 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();
在我启动客户端后,我让它定期post这样的状态:
Console.WriteLine("SSE " + EventClient.Status);
我能看到的是:
- 后端的“订阅”有效。我可以看到请求,它确实启动了 运行 后端线程
- 状态日志显示,进入“正在启动”后不久,状态变为“已启动”
- “开始”状态将保持这种状态,直到达到 30 秒的超时时间。然后它重新连接并继续循环
- 永远不会调用 OnMessage 方法,即使在超时后也不会,就像我在 postman 中看到的那样
附加说明:我还有一个使用 SseEmitter 的服务器端测试实现。在这种情况下,我也可以在“订阅”期间看到应用程序请求,但它会在某个时候超时并出现异常,并且客户端状态永远不会离开“开始”
我的第一个问题显然是:我错过了什么,我永远不会收到消息?
我的第二个问题是:为什么它首先会超时?根据文档,它会定期发送心跳。我需要在 spring 方面采取不同的方法吗?或者我是否需要为心跳实现一个单独的端点?
感谢您的帮助!
编辑:
按照@mythz 的回答并接受在这里使用 ServiceStack 不是一个好主意,我按照以下示例并使用标准 HttpClient 和 StreamReader 实现了一种简单的方法: https://makolyte.com/event-driven-dotnet-how-to-consume-an-sse-endpoint-with-httpclient/
但是,这导致了我之前使用 postman 或我的浏览器遇到的相同问题。 30 秒超时后,所有消息将批量发送。 因此我也改变了后端部分并使用 spring web flux 代替:
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 的 Server Events Feature 以外的任何东西一起使用,这是它所有类型化的服务器事件客户端设计的目的。
例如为了启用断开的网络连接和 auto-retry 连接功能,客户端会定期发回心跳。这只是 ServiceStack 实现中的一个特性,因为 SSE 标准中没有这样的概念。
这只是一个示例,基本上 C# Server Events Client 中的每个 high-level 都使用了 ServiceStack 服务器功能,这些功能在任何其他第 3 方实现中都不存在。