-
Notifications
You must be signed in to change notification settings - Fork 5.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Native HTTP: A streaming body/ServerSentEvents fails #10193
Comments
This is still WIP until denoland/deno#10193 is resolved
@ry it was more than 5 lines, but here is an example: const INDEX_HTML = `<!DOCTYPE html>
<html>
<head></head>
<body>
<h1>Hello world!</h1>
<ul id="events"></ul>
<script>
const sse = new EventSource("/sse");
const ul = document.getElementById("events");
sse.onmessage = (evt) => {
const li = document.createElement("li");
li.textContent = \`message: \${evt.data}\`;
ul.appendChild(li);
};
</script>
</body>
</html>
`;
const encoder = new TextEncoder();
function handleRequest({ request, respondWith }: Deno.RequestEvent) {
let respond: (response: Response) => void;
const p = new Promise<Response>((r) => respond = r);
const respondWithPromise = respondWith(p);
if (request.url === "/sse") {
let id = 0;
let interval = 0;
const body = new ReadableStream({
start(controller) {
console.log("start");
interval = setInterval(() => {
controller.enqueue(
encoder.encode(
`event: message\nid: ${++id}\ndata: { "hello": "deno" }\n\n`,
),
);
}, 1000);
},
cancel() {
console.log("cancelled");
clearInterval(interval);
},
});
respond!(
new Response(body, {
headers: {
"Connection": "Keep-Alive",
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"Keep-Alive": `timeout=${Number.MAX_SAFE_INTEGER}`,
},
}),
);
} else {
respond!(
new Response(INDEX_HTML, {
headers: {
"content-type": "text/html",
},
}),
);
}
return respondWithPromise;
}
for await (const conn of Deno.listen({ port: 8000 })) {
const httpConn = Deno.serveHttp(conn);
(async () => {
for await (const requestEvent of httpConn) {
await handleRequest(requestEvent);
}
})();
}
console.log("started"); Run with:
Navigate to
But I just realised with #10197 the error is now catchable, which means I can work around it. I would still expect the |
I think it should be in addition to. The consequences of
In my early testing (specifically with SSE in fact) it was always catchable, but for a moment before that I thought it wasn't because of a stack trace bug: https://discord.com/channels/684898665143206084/684911491035430919/829893036468338729. Maybe you ran into the same thing? |
🤷 possibly... but then #10197 magically fixed the stack trace too... |
This comment has been minimized.
This comment has been minimized.
emmm, I also encountered this error when using Native HTTP. The relevant code is the same as the sample code of Release Notes. When using wrk2 to test, when wrk2 is finished. Deno was built on the master branch just pulled. |
@juzi5201314 The error is expected, here is the same example with error handling and logging: const body = new TextEncoder().encode("Hello World");
for await (const conn of Deno.listen({ port: 4500 })) {
(async () => {
for await (const { respondWith } of Deno.serveHttp(conn)) {
try {
await respondWith(new Response(body));
} catch (error) {
console.error("%cResponse failed%c:", "color: #909000", "", error);
}
}
})();
} (I still have no idea if using |
I would be able to expect to be able to utilise SSE with the native HTTP, and I can start a request, by setting the appropriate headers and return a
ReableStream
as a body, pushing "chunks" into the controller that represent the events.But when the client attempts to navigate away or refresh, an unrecoverable/uncatchable error occurs:
What I would have expected is that if the
Response
init was a readable stream (as it is in this case) theReadableStream
would be cancelled with the reason, which I would handle in the server code "gracefully".The text was updated successfully, but these errors were encountered: