基於的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();
以上程式碼成功執行後,在當前的執行目錄下將會生成一個大小為 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. 通過大檔案在資料壓縮後傳輸
瀏覽器在傳送請求時,都會攜帶 accept
和 accept-*
請求頭資訊,用於告訴伺服器當前瀏覽器所支援的檔案型別、支援的壓縮格式列表和支援的語言。請求頭中的 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-Encoding
和 Content-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啟動成功`) })
// 實現一個簡單的檔案讀取伺服器(開啟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啟動成功`) })
2. 通過資料分塊傳輸
有場景需要用從資料庫中查詢獲得的資料生成一個大的 HTML 表格的時候,或者需要傳輸大量的圖片的時候,可以通過分塊傳輸實現。
Transfer-Encoding: chunked Transfer-Encoding: gzip, chunked
響應頭 Transfer-Encoding
欄位的值為 chunked
,表示資料以一系列分塊的形式進行傳送。需要注意的是 Transfer-Encoding
和 Content-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其它相關文章!