基於nodejs如何實現http傳輸大檔案?(實踐方法分享)

2022-01-17 22:00:17
基於如何實現http傳輸大檔案?下面本篇文章給大家介紹一下基於nodejs的幾種http檔案傳輸實踐方案,希望對大家有所幫助!

基於的http檔案傳輸方案在現階段的前後端全棧開發中有都很重要的作用,本文我將通過幾種方案實現http傳輸大檔案。在實現功能之前,我們先通過nodejs的fs模組寫入一個大檔案,並在專案中生成一個本地檔案:

const fs = require('fs');
const writeStream = fs.createWriteStream(__dirname + "/file.txt");
for(let i = 0;i <= 100000; i++) {
  writeStream.write(`${i} —— 我是${i}號檔案\n`, "utf-8");
}
writeStream.end();

1.png

以上程式碼成功執行後,在當前的執行目錄下將會生成一個大小為 3.2MB 大小的文字檔案,該檔案將作為以下方案的 「大檔案素材」。在列出大檔案傳輸方案之前,我們先封裝後面即將用到的兩個公共方法: 檔案讀取方法檔案壓縮方法

// 封裝讀取檔案的方法
const readFile = async (paramsData) => {
  return new Promise((resolve, reject) => {
    fs.readFile(paramsData, (err, data) => {
      if(err) {
        reject('檔案讀取錯誤');
      } else {
        resolve(data);
      }
    })
  })
}

// 封裝檔案壓縮方法
const gzip = async (paramsData) => {
  return new Promise((resolve, reject) => {
    zlib.gzip(paramsData, (err, result) => {
      if(err) {
        reject('檔案壓縮錯誤');
      } else {
        resolve(result);
      }
    })
  })
}

1. 通過大檔案在資料壓縮後傳輸

瀏覽器在傳送請求時,都會攜帶 acceptaccept-* 請求頭資訊,用於告訴伺服器當前瀏覽器所支援的檔案型別、支援的壓縮格式列表和支援的語言。請求頭中的 Accept-Encoding 欄位,用於將使用者端能夠理解的內容編碼方式(通常是某種壓縮演演算法)告訴給伺服器端。伺服器端會選擇一個使用者端所支援的方式,並通過響應頭 Content-Encoding 來通知使用者端該選擇,響應頭告訴瀏覽器返回的 JS 指令碼,是經過 gzip 壓縮演演算法處理過的

// 請求頭
accept-encoding: gzip, deflate, br
// 響應頭
cache-control: max-age=2592000 
content-encoding: gzip 
content-type: application/x-javascript

基於 Accept-EncodingContent-Encoding 欄位的瞭解,我們來驗證一下未開啟 gzip 和開啟 gzip 的效果。

// 實現一個簡單的檔案讀取伺服器(沒有開啟gzip)
const server = http.createServer(async (req, res) => {
  res.writeHead(200, {
    "Content-Type": "text/plain;charset=utf-8",
  });
  const buffer = await readFile(__dirname + '/file.txt');
  res.write(buffer);
  res.end();
})
server.listen(3000, () => {
  console.log(`server啟動成功`)
})

2.png

// 實現一個簡單的檔案讀取伺服器(開啟gzip)
const server = http.createServer(async(req, res) => {
  res.writeHead(200, {
    "Content-Type": "text/plain;charset=utf-8",
    "Content-Encoding": "gzip"
  });
  const buffer = await readFile(__dirname + '/file.txt');
  const gzipData = await gzip(buffer);
  res.write(gzipData);
  res.end();
})
server.listen(3000, () => {
  console.log(`server啟動成功`)
})

3.png

2. 通過資料分塊傳輸

有場景需要用從資料庫中查詢獲得的資料生成一個大的 HTML 表格的時候,或者需要傳輸大量的圖片的時候,可以通過分塊傳輸實現。

Transfer-Encoding: chunked
Transfer-Encoding: gzip, chunked

響應頭 Transfer-Encoding 欄位的值為 chunked,表示資料以一系列分塊的形式進行傳送。需要注意的是 Transfer-EncodingContent-Length 這兩個欄位是互斥的,也就是說響應報文中這兩個欄位不能同時出現。

// 資料分塊傳輸
const spilitChunks = async () =>{
  const buffer = await readFile(__dirname + '/file.txt');
  const lines = buffer.toString('utf-8').split('\n');
  let [chunks, i, n] = [[], 0, lines.length];
  while(i < n) {
    chunks.push(lines.slice(i, i+= 10));
  };
  return chunks;
}
const server = http.createServer(async(req, res) => {
  res.writeHead(200, {
    "Content-Type": "text/plain;charset=utf-8",
    "Transfer-Encoding": "chunked",
    "Access-Control-Allow-Origin": "*",
  });
  const chunks = await spilitChunks();
  for(let i =0; i< chunks.length; i++) {
    setTimeout(() => {
      let content = chunks[i].join("&");
      res.write(`${content.length.toString(16)}\r\n${content}\r\n`);
    }, i * 1000);
  }
  setTimeout(() => {
    res.end();
  }, chunks.length * 1000);
})
server.listen(3000, () => {
  console.log(`server啟動成功`)
})

3. 通過資料流的形式傳輸

當使用 Node.js 向用戶端返回大檔案時,使用流的形式來返回檔案流能避免處理大檔案時,佔用過多的記憶體。具體實現方式如下所示。當使用流的形式來返回檔案資料時,HTTP 響應頭 Transfer-Encoding 欄位的值為 chunked,表示資料以一系列分塊的形式進行傳送。

const server = http.createServer((req, res) => {
  res.writeHead(200, {
    "Content-Type": "text/plain;charset=utf-8",
    "Content-Encoding": "gzip",
    "Transfer-Encoding": "chunked"
  });
  fs.createReadStream(__dirname + "/file.txt")
    .setEncoding("utf-8")
    .pipe(zlib.createGzip())
    .pipe(res);
})

server.listen(3000, () => {
  console.log(`server啟動成功`)
})

更多node相關知識,請存取:!!

以上就是基於nodejs如何實現http傳輸大檔案?(實踐方法分享)的詳細內容,更多請關注TW511.COM其它相關文章!