javascript - EventSource riceve tutti i chunk in una volta quando si effettua lo streaming tramite Nextjs API Routes
Problema
Sto cercando di trasmettere dati al mio frontend React tramite EventSources, cosa che funziona in parte. Il problema è che ricevo tutti i blocchi di dati in una volta invece che a intervalli, il che kind of vanifica lo scopo del metodo, dato che ora è praticamente una richiesta GET.
Codice
Sto usando le route API di Next.js e questo è il mio codice su questa route:
res.writeHead(200, {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
Connection: "keep-alive",
});
answerStream.data
.on("data", (chunk: string) => res.write(chunk))
.on("error", (error: Error) => {
console.error(error);
res.end();
})
.on("end", () => res.end());
Questo è il codice nel Frontend:
const eventSource = new EventSource(url);
eventSource.addEventListener("message", e => {
try {
if (e.data == "[DONE]") eventSource.close();
else {
const messageObject = JSON.parse(e.data);
setArticle(state => (state += messageObject?.choices[0]?.text));
}
} catch (error) {
console.log(error);
}
});
eventSource.addEventListener("close", e => {
console.log("Connection closed with the server");
setSubmitting(false);
});
eventSource.addEventListener("error", e => {
setError(e?.message || "Leider ist ein Fehler aufgetreten");
setSubmitting(false);
eventSource.close();
});
Informazioni
C'è qualcosa di sbagliato nella mia implementazione? Oppure Next.js ha un comportamento strano con EventSource?
Risposta n. 1
Soluzione
Ok, ho trovato la soluzione in questa discussione di Github:
Sembra che il problema sia che il middleware aggiunge una codifica gzip che il browser ha negoziato tramite l'intestazione
Per risolvere questo, è necessario sovrascrivere quel comportamento aggiungendo 'Content-Encoding': 'none' agli header sul server:
res.writeHead(200, {
Connection: 'keep-alive',
'Content-Encoding': 'none',
'Cache-Control': 'no-cache',
'Content-Type': 'text/event-stream',
});
In alternativa, si potrebbe usare un server.js personalizzato.
Risposta n. 2
yessssss questo è ciò che stavo cercando, avevo qualcosa di simile, ho passato circa 2 giorni di frustrazione cercando di capirlo. ecco cosa ho finito per fare/avere in aggiunta c'era un'intestazione di chunk con cui stavo sperimentando:
res.setHeader("Content-Type", "text/event-stream");
res.setHeader("Cache-Control", "no-cache");
res.setHeader("Connection", "keep-alive");
res.setHeader("Transfer-Encoding", "chunked");
res.setHeader("Content-Encoding", "none");
