Соединение: keep-alive не хранит сокетное соединение для HTTP-запроса в NodeJS - PullRequest
2 голосов
/ 09 апреля 2020

Я слышал, что заголовок Connection:Keep-Alive скажет серверу на некоторое время поддерживать соединение между клиентом и сервером, чтобы предотвратить попытки при каждом установлении клиентом sh запроса к серверу. Я попытался добавить это в заголовок запроса, но он не сработал, как ожидалось. Соединение с сокетом все еще закрывается при каждом запросе.

Не могли бы вы помочь объяснить, почему это произошло? Я что-то упустил из-за Connection:Keep-Alive или я реализовал это неправильно?

Клиент:

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

Сервер:

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

И это то, что я У вас есть:

Клиент:

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.

и Сервер:

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 версия: 10.15.0


Еще одна вещь, которая делает меня еще более запутанной, заключается в том, что когда я использую telnet localhost 1234 для выполнения запроса:

GET / HTTP/1.1
Connection: Keep-Alive
Host: localhost

Тогда соединение не закрывается, и новое соединение не создается, как ожидалось. Это потому, что te lnet получает Connection: Keep-Alive и сохраняет соединение самостоятельно?

Ответы [ 2 ]

1 голос
/ 09 апреля 2020

Я слышал, что заголовок Connection: Keep-Alive скажет серверу на некоторое время поддерживать соединение между клиентом и сервером, чтобы клиент не каждый раз устанавливал sh запрос к серверу.

Это неправильно. Клиент ничего не требует от сервера, он просто предлагает что-то серверу.

Connection: keep-alive просто говорит серверу, что клиент будет готов держать соединение открытым в порядке чтобы отправить больше запросов. И неявно предполагает, что было бы неплохо, если бы сервер сделал то же самое, чтобы повторно использовать существующее соединение для большего количества запросов. Сервер может затем самостоятельно решить, , будет ли он сохранять соединение открытым после отправки ответа, или немедленно закрывает его, или закрывает после некоторого бездействия или чего-либо еще.

Конечно, это не так Достаточно того, что клиент просто отправляет заголовок HTTP (который в любом случае подразумевается в HTTP / 1.1, поэтому не нужно его отправлять). На самом деле он должен держать TCP-соединение открытым, чтобы отправлять больше запросов по тому же TCP-соединению. Ваша текущая реализация не будет делать этого, как видно из журнала серверов, т.е. клиент сначала закрывает соединение:

SOCKET 1586437549095 END: other end of the socket sends a FIN packet

Для того, чтобы реально поддерживать работу на стороне клиента вы бы использовали агента, который поддерживает соединение открытым через несколько http.request. См. HTTP keep-alive в node.js для получения дополнительной информации.

1 голос
/ 09 апреля 2020

Я думаю, что веб-сокеты - лучшее решение, чем традиционные http / https для вашего случая использования. Соединение между клиентом и сервером будет оставаться активным в веб-сокете, пока сторона клиента не будет закрыта или если вы принудительно закроете соединение.

Node.js пакет веб-розеток

const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', function connection(ws) {
  ws.on('message', function incoming(message) {
    console.log('received: %s', message);
  });

  ws.send('something');
});

клиентские веб-розетки

...