node靜態伺服器斷點續傳實現

akirastorm發表於2018-03-04

當使用者從靜態檔案伺服器上獲取諸如歌曲這樣的流媒體檔案時,如果網路連線斷開,重連後未做處理,就需要重新下載這個檔案。所以為了避免這種情況,我們的伺服器需要一種斷點續傳的功能。而http 1.1中正好規定了一種Range機制,我們可以通過這種機制來進行分片傳輸。

Range

當一個伺服器支援Range時,客戶端可以將需要傳送的內容分成很多份傳送給服務端,服務端可以每次接收部分內容。有了這樣的能力,遇到斷網的情況,我們可以在客戶端記錄下已經傳送的檔案範圍,網路恢復後再將剩餘部分傳送給服務端,這樣就實現了斷點續傳。

Range的在http 1.1中的具體定義可以參考文件:

具體流程如下:

  • 瀏覽器請求內容。

  • 伺服器告訴瀏覽器,該內容可以使用 Accept-Ranges 訊息頭進行分部分請求。

    response.setHeader('Accept-Ranges', 'bytes');
    複製程式碼
  • 瀏覽器重新傳送請求,用 Range 訊息頭告訴伺服器需要的內容範圍。

    傳送的Range格式:位元組數(bytes)= (開始)-(結束)

    這是瀏覽器告知伺服器所需分部分內容範圍的訊息頭. 注意開始和結束位置是都包括在內的,而且是從0開始的. 這個訊息頭也可以不傳送兩個位置,其含義如下:

    • 如果結束位置被去掉了,伺服器會返回從宣告的開始位置到整個內容的結束位置內容的最後一個可用位元組。
    • 如果開始位置被去掉了,結束位置引數可以被描述成從最後一個可用的位元組算起可以被伺服器返回的位元組數。

而伺服器會分如下兩種情況響應瀏覽器的請求:

  • 如果範圍是合理的,伺服器會返回所請求的部分內容,並帶上 206 Partial Content 狀態碼. 當前內容的範圍會在 Content-Range 訊息頭中申明。 傳送的Content-Range格式:位元組數(bytes)=(開始)-(結束)/(總數)
  • 如果範圍是不可用的(例如,比內容的總位元組數大), 伺服器會返回 416 請求範圍不合理 Requested Range Not Satisfiable 狀態碼. 可用的範圍也會在 Content-Range 訊息頭中宣告。

nodejs簡單實現

getStream(req, res, filepath, statObj) {
    let start = 0;
    let end = statObj.size - 1;
    let range = req.headers['range'];
    if (range) {
        res.setHeader('Accept-Range', 'bytes');
        res.statusCode = 206;
        let result = range.match(/bytes=(\d*)-(\d*)/);
        if (result) {
            start = isNaN(result[1]) ? start : parseInt(result[1]);
            end = isNaN(result[2]) ? end : parseInt(result[2]) - 1;
        }
    }
    return fs.createReadStream(filepath, {
        start, end
    });
}
複製程式碼

待續

自我小結

在搭建node靜態伺服器過程中學習利用Http1.1的Range來實現斷點續傳功能

參考資料

相關文章