NodeJS新Agent()和HTTP Keep-Alive标头之间的区别..?

时间:2017-06-20 09:47:25

标签: node.js axios keep-alive

我使用axios发出HTTP请求。

axios提供了在节点中使用时在request config中指定new http.Agent()的选项。

http Agent选项包括:

const agentOptions = {
  keepAlive: true,      // Keep sockets around even when there are no outstanding requests, so they can be used for future requests without having to reestablish a TCP connection. Defaults to false
  keepAliveMsecs: 1000, // When using the keepAlive option, specifies the initial delay for TCP Keep-Alive packets. Ignored when the keepAlive option is false or undefined. Defaults to 1000.
  maxSockets: Infinity, // Maximum number of sockets to allow per host. Defaults to Infinity.
  maxFreeSockets: 256   // Maximum number of sockets to leave open in a free state. Only relevant if keepAlive is set to true. Defaults to 256.
}

HTTP header还有timeoutmax选项。

这些选项似乎不排成一行(keepAliveMsecsmaxSocketsmaxFreeSockets vs timeoutmax),这表明它们是不同。

Node new Agent({ keepAlive: true })与HTTP标头Keep-Alive: timeout=5, max=1000之间的区别是什么?

1 个答案:

答案 0 :(得分:3)

首先,感谢您的提问,我之前从未对保持活力有太多了解。

HTTP标头Keep-Alive: timeout=5, max=1000只是随HTTP请求发送的标头。将其视为在两个主机(客户端和服务器)之间进行通信的一种方式。主持人说:“嘿,请保持连接活跃”。这对于现代浏览器是自动的,服务器可能会实现也可能不会实现。代理人的keepAlive: truedocumentation所说

  

不要与Connection标头的keep-alive值混淆。

这意味着keepAlive: false!= Connection: close。它实际上与标题没有任何关系。该代理将使用套接字和 HTTP客户端在TCP级别处理事务。

  

keepAlive boolean即使没有未处理的请求,也保留套接字,因此它们可用于将来的请求而不必重新建立TCP连接

将代理用于HTTP客户端后,将立即使用Connection: Keep-Alive除非keepAlive设置为falsemaxSockets设置为Infinity

const options = {
  port: 3000,
  agent: new http.Agent({ 
        keepAlive: false ,
        maxSockets: Infinity,
    })
};//----> Connection: close

agent到底是什么?

  

代理负责管理HTTP客户端的连接持久性和重用。它为给定的主机和端口维护一个待处理请求队列,为每个主机和端口重用单个套接字连接,直到队列为空,此时该套接字要么被销毁,要么被放入池中,以便再次用于请求到相同的主机和端口。它是被销毁还是被池化取决于keepAlive选项。

     

池连接为它们启用了TCP Keep-Alive,但是服务器仍可以关闭空闲连接,在这种情况下,它们将从池中删除,并且当对该主机和主机发出新的HTTP请求时将建立新的连接。港口。服务器也可能拒绝允许通过同一连接的多个请求,在这种情况下,必须为每个请求重新建立连接,并且不能将其合并。代理仍会向该服务器发出请求,但每个请求都将通过新的连接发生。

据我所知,关于超时 max ,在为Apache添加配置时会自动设置这些设置

#
# KeepAlive: Whether or not to allow persistent connections (more than
# one request per connection). Set to "Off" to deactivate.
#
KeepAlive On

#
# MaxKeepAliveRequests: The maximum number of requests to allow
# during a persistent connection. Set to 0 to allow an unlimited amount.
# We recommend you leave this number high, for maximum performance.
#
MaxKeepAliveRequests 100

#
# KeepAliveTimeout: Number of seconds to wait for the next request from the
# same client on the same connection.
#
KeepAliveTimeout 5

给出

Connection:Keep-Alive
Keep-Alive:timeout=5, max=100

但是这些与NodeJS无关吗?我会让更多有经验的人回答这个问题。无论如何,除非如上所述,否则除非将Connection: Keep-Alive设置为keepAlive并将false设置为maxSockets,否则代理将不会进行设置,也不会修改Infinity

但是,要使代理配置具有任何含义,必须将Connection设置为Keep-Alive


好的,现在做一个小实验,看看代理在工作!

我已经设置了一个客户端进行测试(由于axios始终使用http.agent作为代理,因此我只使用了http)。

const http = require('http');

const options = {
  port: 3000,
  agent: new http.Agent({ 
        keepAlive: true,
        maxSockets: 2,
    }),
  // headers: {
  //     'Connection': 'close'
  // }
};

var i = 0;

function request() {
    console.log(`${++i} - 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(function(){ request(); }, 3000); // send a request every 3 seconds

服务器是快速应用程序(我将跳过详细信息)

server.on('connection', function(socket) {
        socket.id = shortid.generate();
          //socket.setTimeout(500)
          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);
        });
    });

要让您看到keepAlive: false!= Connection: close,请将keepAlive设置为false并查看服务器端会发生什么情况。

agent: new http.Agent({ 
        keepAlive: false,
        maxSockets: 20
    })

服务器

enter image description here

客户

enter image description here

如您所见,我没有将maxSockets设置为Infinity,因此即使代理中的keepAlive设置为false,Connection头也设置为Keep-Alive。但是,每次将请求发送到服务器时,每个请求后都会立即关闭服务器上的套接字。让我们看看将keepAlive设置为true会发生什么。

服务器

enter image description here

客户

enter image description here

这一次,仅使用了一个插槽。客户端和服务器之间存在持久连接,并且该连接超出了单个请求。

由于great article,我了解到的一件事是,在Firefox上,一次最多可以有6个并发持久连接。而且,您可以通过将maxSockets设置为6来使用代理来重现此内容。出于测试目的,我将其设置为2。此外,我不会从服务器返回任何内容,因此连接将被挂起。

agent: new http.Agent({ 
        keepAlive: true,
        maxSockets: 2,
    }),
//res.send('response from the server');

服务器

enter image description here

客户

enter image description here

客户端继续发送请求,但服务器仅接收到两个请求。两分钟后,请参见http_server_timeout

  

假定套接字超时之前闲置的毫秒数。

两个新请求被接受。实际上,客户端已经将后续请求排队,一旦服务器释放了套接字,客户端就可以从队列中发送两个新请求。

所以,我希望这会有所帮助。