【问题标题】:Connection:keep-alive is not keeping the socket connection for HTTP request in NodeJSConnection:keep-alive 没有为 NodeJS 中的 HTTP 请求保持套接字连接
【发布时间】:2020-07-22 03:34:07
【问题描述】:

我听说Connection:Keep-Alive 标头会告诉服务器将客户端和服务器之间的连接保持一段时间,以防止每次客户端向服务器建立请求时都要付出努力。我试图将其添加到请求的标头中,但没有按预期工作。每次请求时,套接字连接仍然关闭。

您能帮忙解释一下为什么会这样吗?我是否遗漏了有关 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

然后连接没有关闭,并且没有按预期创建新连接。那是因为 telnet 接收到Connection: Keep-Alive 并自行保持连接?

【问题讨论】:

    标签: node.js sockets http keep-alive


    【解决方案1】:

    对于您的用例,我认为 websockets 是比传统 http/https 更好的解决方案。客户端和服务器之间的连接将在 websocket 上保持活动状态,直到客户端关闭,或者如果您强制关闭连接。

    Node.js websocket package

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

    Client side websockets

    【讨论】:

    • 是的,你是对的。但是我的实验要求客户端是 HTTP 客户端而不是 websocket 订阅者。为了更多地了解Connection:keep-alive,我想使用http而不是websocket,因为websocket已经自己处理了。
    • 我明白了,http 长轮询将是你想要的。但是,使用 http 的工作方式,连接并不意味着保持打开状态。 dev.to/moz5691/websocket-vs-long-polling-http-412f 祝你好运,
    【解决方案2】:

    我听说 Connection:Keep-Alive 标头会告诉服务器将客户端和服务器之间的连接保持一段时间,以防止每次客户端向服务器建立请求时的努力。

    这是错误的。客户端不要求服务器提供任何东西,它只是向服务器建议一些东西。

    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 in node.js 了解更多信息。

    【讨论】:

    • 感谢您的回答@Steffen Ullrich。所以关于telnet,我的假设是正确的。 Telnet 保持连接,因为它在请求中看到了Connection: Keep-Alive。它会创建一个持久连接并告诉服务器这一点?
    • @ToanQuocHo:telnet 保持连接打开,因为这是 telnet 所做的。 Telnet 不知道 HTTP,因此不会解释您发送的任何数据。只有当您明确指示它这样做时,它才会关闭连接,或者当然,如果对等方关闭连接。
    • 我明白了。那么关于连接机制,它与Connection: Keep-Alive 无关,但客户端必须先处理该机制,然后才能将该信息发送到服务器,对吧?就像使用代理来保持连接一样。
    • @ToanQuocHo:正如我所说:Connection: keep-alive 只是通知服务器客户端愿意保持连接打开以发送更多请求。它对 TCP 连接没有任何神奇的作用。从 TCP 的角度来看,这只是没有意义的文本。
    • 知道了,谢谢@Steffen。
    猜你喜欢
    • 2020-06-17
    • 1970-01-01
    • 2013-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-01
    相关资源
    最近更新 更多