I have heard that Connection:Keep-Alive
header will tell the server to keep the connection between client and server for a while to prevent the effort for each time client establish a request to server. I tried to add that to the request's header but it didn't work out as expected. The socket connection still close on each request.
Could you please help to explain why that happened? Did I missing something about Connection:Keep-Alive
or did I implement it the wrong way?
Client:
const http = require("http");
const options = {
port: 4000,
headers: {
connection: "keep-alive",
},
};
function request() {
console.log(`making a request`);
const req = http.request(options, (res) => {
console.log(`STATUS: ${res.statusCode}`);
console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
res.setEncoding("utf8");
res.on("data", (chunk) => {
console.log(`BODY: ${chunk}`);
});
res.on("end", () => {
console.log("No more data in response.");
});
});
req.on("error", (e) => {
console.error(`problem with request: ${e.message}`);
});
req.end();
}
setInterval(() => {
request();
}, 3000);
Server:
const http = require("http");
const server = http.createServer((req, res) => {
setTimeout(() => {
res.end();
}, 500);
});
server.on("connection", function (socket) {
socket.id = Date.now();
console.log(
"A new connection was made by a client." + ` SOCKET ${socket.id}`
);
socket.on("end", function () {
console.log(
`SOCKET ${socket.id} END: other end of the socket sends a FIN packet`
);
});
socket.on("timeout", function () {
console.log(`SOCKET ${socket.id} TIMEOUT`);
});
socket.on("error", function (error) {
console.log(`SOCKET ${socket.id} ERROR: ` + JSON.stringify(error));
});
socket.on("close", function (had_error) {
console.log(`SOCKET ${socket.id} CLOSED. IT WAS ERROR: ` + had_error);
});
});
server.on("clientError", (err, socket) => {
socket.end("HTTP/1.1 400 Bad Request\r\n\r\n");
});
server.listen(4000);
And this is what I've got:
Client:
making a request
STATUS: 200
HEADERS: {"date":"Thu, 09 Apr 2020 13:05:44 GMT","connection":"keep-alive","content-length":"81"}
No more data in response.
making a request
STATUS: 200
HEADERS: {"date":"Thu, 09 Apr 2020 13:05:47 GMT","connection":"keep-alive","content-length":"81"}
No more data in response.
making a request
STATUS: 200
HEADERS: {"date":"Thu, 09 Apr 2020 13:05:50 GMT","connection":"keep-alive","content-length":"81"}
No more data in response.
and Server:
A new connection was made by a client. SOCKET 1586437543111
{ connection: 'keep-alive', host: 'localhost:1234' }
SOCKET 1586437543111 END: other end of the socket sends a FIN packet
SOCKET 1586437543111 CLOSED. IT WAS ERROR: false
A new connection was made by a client. SOCKET 1586437546091
{ connection: 'keep-alive', host: 'localhost:1234' }
SOCKET 1586437546091 END: other end of the socket sends a FIN packet
SOCKET 1586437546091 CLOSED. IT WAS ERROR: false
A new connection was made by a client. SOCKET 1586437549095
{ connection: 'keep-alive', host: 'localhost:1234' }
SOCKET 1586437549095 END: other end of the socket sends a FIN packet
SOCKET 1586437549095 CLOSED. IT WAS ERROR: false
NodeJS version: 10.15.0
There is one more thing makes me even more confuse is that when I use telnet localhost 1234
to make a request:
GET / HTTP/1.1
Connection: Keep-Alive
Host: localhost
Then the connection is not close, and no new connection being created as expected. Is that because telnet receive Connection: Keep-Alive
and keep the connection by itself?
I have heard that Connection:Keep-Alive header will tell the server to keep the connection between client and server for a while to prevent the effort for each time client establish a request to server.
This is wrong. The client does not demand anything from the server, it just suggests something to the server.
Connection: keep-alive
just tells the server that the client would be willing to keep the connection open in order to send more requests. And implicitly suggests that it would be nice if the server would do the same in order to reuse the existing connection for more requests. The server then can decide by its own if it keeps the connection open after the response was send or closes it immediately or closes it after some inactivity or whatever.
Of course, it is not enough that the client just sends the HTTP header (which is implicit with HTTP/1.1 anyway so no need to send it). It must actually keep the TCP connection open in order to send more requests on the same TCP connection. Your current implementation will not do this as can be seen from the servers log, i.e. the client is closing the connection first:
SOCKET 1586437549095 END: other end of the socket sends a FIN packet
In order to have real keep-alive on the client side you would use an agent which keeps the connection open through multiple http.request
. See HTTP keep-alive in node.js for more.