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埠傳送請求,結束後再看下這個連線是否還在。
...
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。