長連線及在Node中的應用——HTTP/1.1 keep-alive

m_ing發表於2019-03-03

HTTP請求都要經過TCP三次握手建立連線,四次分手斷開連,如果每個HTTP請求都要建立TCP連線的話是極其費時的,因此HTTP/1.1中瀏覽器預設開啟了Connection: keep-alive

長連線及在Node中的應用——HTTP/1.1 keep-alive
請求頭中的這個屬性的作用可以在請求完成後,保持TCP連線一段時間而不關閉,如果這個期間又有HTTP請求的話,直接使用這個TCP連線,省去了建立新的連線的時間。由於是瀏覽器預設新增的,所以經常沒有關注。接下來看下在Node服務中發起HTTP請求是什麼樣子。

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

長連線及在Node中的應用——HTTP/1.1 keep-alive
可以看到,請求完成後被請求的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這個配置

長連線及在Node中的應用——HTTP/1.1 keep-alive

request({
    method: 'GET',
    uri: 'http://xxx:8887/xxx',
    forever: true // 這個很重要 開啟keep-alive
}, (error, response, body) => {
    console.log('response', response);
});
複製程式碼

長連線及在Node中的應用——HTTP/1.1 keep-alive
這次,在請求結束後,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'
        });
    });
});
複製程式碼

長連線及在Node中的應用——HTTP/1.1 keep-alive
可以看到只有第一次的請求消耗了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'
        });
    });
});
複製程式碼

長連線及在Node中的應用——HTTP/1.1 keep-alive
可以看到HTTP/1.1並行請求的時候會建立多個TCP連線,在瀏覽器中針對同一域名只可以同時建立6個連線,雖然Node中沒有這個限制,但如何讓多個同時的請求也使用同一個TCP連線呢?當然是有辦法的,這就需要使用到HTTP/2.0中的單一長連線了,之後再來分析HTTP/2.0。

相關文章