I have implemented a simple streaming server using Node.js and Express. The server sends chunks of data at regular intervals using a POST endpoint. However, I've observed that the request close event is triggered immediately when there is data in the request, even though I have not explicitly closed the request from the client side.
Here's the code snippet for my POST request streaming example:
const express = require("express");
const app = express();
app.use(express.json());
// POST request streaming example
app.post("/stream-post", (req, res) => {
res.setHeader("Content-Type", "text/plain");
res.setHeader("Transfer-Encoding", "chunked");
const intervalId = setInterval(() => {
res.write("This is a chunk of streaming data.\n");
}, 1000);
req.on("close", () => {
clearInterval(intervalId);
res.end();
});
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server listening on port ${PORT}`);
});
When I send a POST request to this endpoint with data using the following cURL command, the close event is triggered immediately:
curl -i --no-buffer -X POST http://localhost:3000/stream-post \
-H "Content-Type: application/json" \
-d '{
"this is a test": "value"
}'
However, when there is no data in the request, the close event is not triggered immediately.
What could be the reason behind this behavior? Is there any way to ensure that the close event is only triggered when the request is actually closed, regardless of whether there is data in the request or not?
A Node http.IncomingMessage
close
event is not the end of the connection. The event signals when a complete HTTP request message has been received and successfully parsed, but can also be triggered if the connection happens to close before then.
The difference in body/no body behaviour is likely related to the Express body-parser
middleware. When a body exists, it processes the body stream and triggers the request close event. When there is no body, the request passes straight on to the next middleware.
Stop streaming when the response close
event fires. That occurs when the client has gone.
app.post("/stream-post", (req, res) => {
res.status(200)
res.setHeader("Content-Type", "text/plain");
res.setHeader("Transfer-Encoding", "chunked");
const intervalId = setInterval(() => {
console.log('write chunk')
res.write("This is a chunk of streaming data.\n");
}, 1000);
res.on("close", () => {
console.log('res closed')
clearInterval(intervalId);
});
});