javascript - EventSource får alla delar samtidigt när den streamas via Nextjs API-rutter


Problem

Jag försöker strömma data till mitt React-frontend via EventSources, vilket fungerar på ett sätt. Problemet är att jag mottar alla datadelar på en gång istället för en efter en. Vilket på sätt och vis motverkar syftet med metoden eftersom det i princip nu är en GET-förfrågan.

Kod

Jag använder Next.js API-rutter och detta är min kod på denna rutt:

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());

Detta är koden i 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();
  });

Info

Finns det något fel i min implementering? Eller har Next.js en konstig hantering av EventSource?

Svar #1

Lösning

Okej, jag har hittat lösningen i denna Github-diskussion:

Det verkar som att problemet är att mellanprogramvaran lägger till en gzip-kodning som webbläsaren har förhandlat fram med hjälp av headern

För att åtgärda detta behöver man skriva över det beteendet genom att lägga till 'Content-Encoding': 'none' i rubrikerna på servern:

res.writeHead(200, {
    Connection: 'keep-alive',
    'Content-Encoding': 'none',
    'Cache-Control': 'no-cache',
    'Content-Type': 'text/event-stream',
  });

Alternativt kan man använda en anpassad server.js.

Svar #2

jajaaaaa detta är vad jag letade efter, hade något liknande, tillbringade ungefär 2 dagar med frustration för att försöka lista ut det. här är vad jag slutade med/gjorde utöver det fanns en blockrubrik som jag experimenterade med:

  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");