fetchEventSource() repeats request indefinitely
I have SSE-endpoint http://localhost/sse-endpoint that returns next data:
data:{text: "He"}
id:0
data:{text: "ll"}
id:2
data:{text: "o,"}
id:4
data:{text: " u"}
id:6
data:{text: "se"}
id:8
data:{text: "r!"}
id:10
I use this client code to fetch data:
import { fetchEventSource } from "@microsoft/fetch-event-source";
console.log('Start');
fetchEventSource("http://localhost/sse-endpoint"), {
method: "POST",
onmessage(ev) {
console.log('Received data');
console.log(ev.data);
}
});
Expected output:
Start
Received data
{text: "He"}
Received data
{text: "ll"}
Received data
{text: "o,"}
Received data
{text: " u"}
Received data
{text: "se"}
Received data
[{text: "r!"}
Actual output:
Start
Received data
{text: "He"}
Received data
{text: "ll"}
Received data
{text: "o,"}
Received data
{text: " u"}
Received data
{text: "se"}
Received data
[{text: "r!"}
Received data
{text: "He"}
Received data
{text: "ll"}
Received data
{text: "o,"}
Received data
{text: " u"}
Received data
{text: "se"}
Received data
[{text: "r!"}
// Output continues infinitely
In devtools tab "Network" I can see that requests to /sse-endpoint continues indefinitely
make sure your server code is responding with:
res.setHeader('Cache-Control', 'no-cache, no-transform');
res.setHeader('Connection', 'keep-alive');
res.setHeader('Content-Type', 'text/event-stream');
res.flushHeaders();
make sure your server code is responding with:
res.setHeader('Cache-Control', 'no-cache, no-transform'); res.setHeader('Connection', 'keep-alive'); res.setHeader('Content-Type', 'text/event-stream'); res.flushHeaders();
It's external server and I can't control it, but it has following HTTP response headers:
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Connection: keep-alive
Content-Type: text/event-stream
This will only happen when server keeps sending you events. On message only fires when server sends events. To mitigate this (since you don't have control over the server): call abort using an AbortController once you get a set of messages you need and reconnect when you need them again.
Set the "openWhenHidden" true and can be solved.
fetchEventSource(API, { openWhenHidden: true })
vConsole may cause this issue, remove it.
Set the "openWhenHidden" true and can be solved.
fetchEventSource(API, { openWhenHidden: true })
This Solved my issue, thanks alot. It would be helpful if you could provide some explanation about this.
Set the "openWhenHidden" true and can be solved.
fetchEventSource(API, { openWhenHidden: true })This Solved my issue, thanks alot. It would be helpful if you could provide some explanation about this.
@Alwaz * If openWhenHidden is true, it will keep the request open even if the document is hidden. * By default, fetchEventSource will close the request and reopen it * automatically when the document becomes visible again. https://github.com/Azure/fetch-event-source/blob/main/src/fetch.ts#L45C5-L48C62
Set the "openWhenHidden" true and can be solved.
fetchEventSource(API, { openWhenHidden: true })This Solved my issue, thanks alot. It would be helpful if you could provide some explanation about this.
@Alwaz * If openWhenHidden is true, it will keep the request open even if the document is hidden. * By default, fetchEventSource will close the request and reopen it * automatically when the document becomes visible again. https://github.com/Azure/fetch-event-source/blob/main/src/fetch.ts#L45C5-L48C62
This was causing my issue, when I alt tab out and tab back in, it sends another request
Ran into this today and found another possible cause. Looks like fetchEventSource does not provide a default error handler. I had a bug in my onmessage, but it was getting swallowed up with no logs. Just shove console.error into the options and you'll start seeing the real issue in the console.
await fetchEventSource("http://localhost:3000/stream", {
onmessage,
onerror: console.error,
})
In my case, I set "openWhenHidden" to False, but the request never close. It will always run into "onerror" but not "onclose". So I throw an error In "onerror" then it stop. btw, I run it in a Android webview page.