I recently tried to connect my Yew frontend app to an actix-web SSE server I use to send events to the page. I tried different approaches and crates like EventSource from “web_sys”, “sse_client” and “gloo_net” but none of them worked.
Sometimes I got CORS errors but now I only get a connection error by the Browser.
For a while the Browser console also said, my callback function got either dropped or was called recursively.
I know that my SSE server works at least in some way. With curl I can connect without problem and receive all events that are emitted. So the problem should be related to my frontend code.
I uploaded a working example with server and client to GitHub using gloo_net crate:
https://github.com/heureka-code/sse-test
This is the part of the frontend that matters:
#[function_component(App)]
pub fn app() -> Html {
use wasm_bindgen_futures::spawn_local;
let src = gloo_net::eventsource::futures::EventSource::new("localhost:9000/sse");
use futures::StreamExt;
log::info!("{src:?}"); // status: Connecting
if let Ok(mut event_source) = src {
let mut stream1 = event_source.subscribe("test-event").unwrap();
spawn_local(async move {
log::info!("{event_source:?}"); // status: Connecting
log::info!("First: {:?}", stream1.next().await); // Some(Err(ConnectionError))
log::info!("{event_source:?}"); // status: Closed
while let Some(Ok((event_type, msg))) = stream1.next().await {
log::warn!("New message: {event_type} {msg:?}");
}
log::info!("Finished");
});
log::info!("After spawn");
}
html!()
}
This is the SSE route of the server:
use actix_web::{get, Responder};
use actix_web_lab::sse;
use std::time::Duration;
use tokio::time::sleep;
#[get("/sse")]
async fn stream_updates() -> impl Responder {
let (tx, rx) = tokio::sync::mpsc::channel(10);
tokio::spawn(async move {
for i in 0..10 {
let _ = tx
.send(sse::Data::new(i.to_string()).event("test-event").into())
.await;
sleep(tokio::time::Duration::from_secs(1)).await;
}
});
let sse = sse::Sse::from_infallible_receiver(rx).with_retry_duration(Duration::from_secs(10));
let sse = sse
.customize()
.append_header(("Access-Control-Allow-Origin", "*"))
.append_header(("Access-Control-Allow-Headers", "content-type"));
return sse;
}
I tried different libraries but never received helpful error messages.
You can start the server inside it’s directory as normal with cargo run
.
The frontend code can be executed like explained here:
https://yew.rs/docs/getting-started/introduction
When running you can look at the browser’s console or with curl at
localhost:9000/sse
If my system is relevant for the problem, I’m using Linux and Firefox.
Maybe it’s a simple solution but I don’t know what to try next. Maybe someone could help?