HTTP请求都要经过TCP三次握手建立连接,四次分手断开连,如果每个HTTP请求都要建立TCP连接的话是极其费时的,因此HTTP/1.1中浏览器默认开启了Connection: keep-alive
。
let request = require('request');router.get('/http1', (req, res, next) => { request({ method: 'GET', uri: 'http://xxx:8887/xxx' }, (error, response, body) => { console.log('response', response); });});复制代码
在Node中我们经常使用是request模块来发送HTTP请求,那么就做一个实验,先向这个8887端口发送请求,结束后再看下这个连接是否还在。
... 可以看到,请求完成后被请求的8887端口已经没有连接了。也就是,如果再次请求还需要建立TCP连接,那么就像浏览器一样在请求头中设置一下Connection: keep-alive
。 request({ method: 'GET', uri: 'http://xxx:8887/xxx', headers: { Connection: 'keep-alive' }}, (error, response, body) => { console.log('response', response);});复制代码
结果还是和上面一样,连接数还是0,翻看request的文档,原来并不是这么设置,而是使用forever这个配置
request({ method: 'GET', uri: 'http://xxx:8887/xxx', forever: true // 这个很重要 开启keep-alive}, (error, response, body) => { console.log('response', response);});复制代码这次,在请求结束后,8887端口还存在一个连接,
keep-alive
已经生效了,这个连接会保持多久?一般在nginx中有设置,默认65s。 接下来看下,使用长连接后,是否省去了TCP的时间。 串行上面的请求10次来实验。 router.get('/http1', (req, res, next) => { async function fn() { for (let i = 0; i < 10; i ++) { await new Promise((resolve, reject) => { request({ method: 'GET', uri: 'http://xxx:8887/xxx', time: true, // 配置这个属性可以看到时间信息 forever: true }, (error, response, body) => { console.log('timingPhases', response.timingPhases); resolve(); }); }); } return 'success'; } fn().then(()=>{ res.json({ msg: 'end' }); });});复制代码可以看到只有第一次的请求消耗了tcp的时间,之后的都是复用了之前建立的TCP连接,至于dns为0是因为没有使用域名。 以上就是在Node中如何使用
keep-alive
及验证。 顺便看下,如果是并行请求,会建立多少个TCP连接呢? router.get('/http1con', (req, res, next) => { let promiseArr = []; for (let i = 0; i < 10; i ++) { let newP = new Promise((resolve, reject) => { request({ method: 'GET', uri: 'http://xxx:8887/xxx', time: true, forever: true }, (error, response, body) => { resolve(); }); }); promiseArr.push(newP); } Promise.all(promiseArr).then(() => { res.json({ 'msg': 'end' }); });});复制代码可以看到HTTP/1.1并行请求的时候会建立多个TCP连接,在浏览器中针对同一域名只可以同时建立6个连接,虽然Node中没有这个限制,但如何让多个同时的请求也使用同一个TCP连接呢?当然是有办法的,这就需要使用到HTTP/2.0中的单一长连接了,之后再来分析HTTP/2.0。