国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

這篇具有很好參考價(jià)值的文章主要介紹了基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

目錄

前言

基礎(chǔ)下載功能

進(jìn)階下載功能

單片下載

多片下載?

瀏覽器發(fā)送預(yù)檢(preflight)請求

express 不支持多段 range

multipart/** 搭配 boundary=**

分片下載功能

“只讀的” ArrayBuffer 對象

DataView 子類?Uint8Array?操作二進(jìn)制數(shù)據(jù)

Blob + createObjectURL 創(chuàng)建 url

全部代碼

通用的文件分片下載工具

拿到文件的大小 接口

分片函數(shù)

mergeArrayBuffer 函數(shù)

全部代碼

總結(jié)


前言

技術(shù)都寫在文檔里了。有用的文章,值得看第二遍

基礎(chǔ)下載功能

下載文件是一個(gè)常見的需求,只要服務(wù)端設(shè)置 Content-Disposition 為 attachment 就可以。

比如這樣:

 const express = require('express');
 const app = express();

 app.get('/aaa',(req, res, next) => {
     res.setHeader('Content-Disposition','attachment; filename="guang.txt"')
     res.end('guangguang');
 })

 app.listen(3000, () => {
     console.log(`server is running at port 3000`)
 })

設(shè)置 Cotent-Disposition 為 attachment,指定 filename。

然后 html 里加一個(gè) a 標(biāo)簽:

 <!DOCTYPE html>
 <html lang="en">
 <body>
     <a href="http://localhost:3000/aaa">download</a>
 </body>
 </html>

跑起靜態(tài)服務(wù)器:

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

點(diǎn)擊鏈接就可以下載:

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

????????如果文件比較大,比如 500M,當(dāng)你下載了 499M 的時(shí)候突然斷網(wǎng)了,這時(shí)候下載就失敗了,你就要從頭再重新下載一次。體驗(yàn)就很不爽。

進(jìn)階下載功能

單片下載

????????能不能基于上次下載的地方接著下載,也就是斷點(diǎn)續(xù)傳呢?可以的,HTTP 里有這部分協(xié)議,就是 range 相關(guān)的 header。看下 MDN 對 range 的解釋:

Range
The Range 是一個(gè)請求首部,告知服務(wù)器返回文件的哪一部分。在一個(gè) Range 首部中,可以一次性請求多個(gè)部分,服務(wù)器會(huì)以 multipart 文件的形式將其返回。如果服務(wù)器返回的是范圍響應(yīng),需要使用 206 Partial Content 狀態(tài)碼。假如所請求的范圍不合法,那么服務(wù)器會(huì)返回 416 Range Not Satisfiable 狀態(tài)碼,表示客戶端錯(cuò)誤。服務(wù)器允許忽略 Range 首部,從而返回整個(gè)文件,狀態(tài)碼用 200 。

就是說你可以通過 Range 的 header 告訴服務(wù)端下載哪一部分內(nèi)容。

比如這樣:

 Range: bytes=200-1000

????????就是下載 200-1000 字節(jié)的內(nèi)容(兩邊都是閉區(qū)間),服務(wù)端返回 206 的狀態(tài)碼,并帶上這部分內(nèi)容。

可以省略右邊部分,代表一直到結(jié)束:

 Range: bytes=200-

也可以省略左邊部分,代表從頭開始:

 Range: bytes=-1000

而且可以請求多段 range,服務(wù)端會(huì)返回多段內(nèi)容:

 Range: bytes=200-1000, 2000-6576, 19000-

知道了 Range header 的格式,我們來試一下吧!

添加這樣一個(gè)路由:

 app.get('/', (req, res, next) => {
     res.setHeader('Access-Control-Allow-Origin', '*');

     res.download('index.txt', {
         acceptRanges: true
     })
 })

設(shè)置允許跨域請求。res.download 是讀取文件內(nèi)容返回,acceptRanges 選項(xiàng)為 true 就是會(huì)處理 range 請求(其實(shí)默認(rèn)就是 true)。文件 index.txt 的內(nèi)容是這樣的:

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

然后在 html 里訪問一下這個(gè)接口:

 <!DOCTYPE html>
 <html lang="en">
 <head>
     <script src="https://www.unpkg.com/axios@1.3.5/dist/axios.min.js"></script>
 </head>
 <body>
     <script>
         axios.get('http://localhost:3000', {
             headers: {
                 Range: 'bytes=0-4',
             }
         }).then((res) => {
             console.log(res.data);
         }).catch((err) => {
             console.log(err);
         })
     </script>
 </body>
 </html>

訪問頁面,可以看到返回的是 206 的狀態(tài)碼!

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

????????這時(shí)候 Content-Length 就代表返回的內(nèi)容的長度。還有個(gè) Content-Range 代表當(dāng)前 range 的長度以及總長度。

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

當(dāng)然,你也可以訪問 5 以后的內(nèi)容

 <!DOCTYPE html>
 <html lang="en">
 <head>
     <script src="https://www.unpkg.com/axios@1.3.5/dist/axios.min.js"></script>
 </head>
 <body>
     <script>
         axios.get('http://localhost:3000', {
             headers: {
                 Range: 'bytes=5-',
             }
         }).then((res) => {
             console.log(res.data);
         }).catch((err) => {
             console.log(err);
         })
     </script>
 </body>
 </html>

返回的是這樣的:

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

????????這倆連接起來不就是整個(gè)文件的內(nèi)容么?這樣就實(shí)現(xiàn)了斷點(diǎn)續(xù)傳!我們再來試試如果超出 range 會(huì)怎么樣:

 <!DOCTYPE html>
 <html lang="en">
 <head>
     <script src="https://www.unpkg.com/axios@1.3.5/dist/axios.min.js"></script>
 </head>
 <body>
     <script>
         axios.get('http://localhost:3000', {
             headers: {
                 Range: 'bytes=500-600',
             }
         }).then((res) => {
             console.log(res.data);
         }).catch((err) => {
             console.log(err);
         })
     </script>
 </body>
 </html>

請求 500-600 字節(jié)的內(nèi)容,這時(shí)候響應(yīng)是這樣的:

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

多片下載?

????????返回的是 416 狀態(tài)碼,代表 range 不合法。Range 不是還可以設(shè)置多段么?多段內(nèi)容是怎么返回的呢?我們來試一下:

 <!DOCTYPE html>
 <html lang="en">
 <head>
     <script src="https://www.unpkg.com/axios@1.3.5/dist/axios.min.js"></script>
 </head>
 <body>
     <script>
         axios.get('http://localhost:3000', {
             headers: {
                 Range: 'bytes=0-2,4-5,7-',
             }
         }).then((res) => {
             console.log(res.data);
         }).catch((err) => {
             console.log(err);
         })
     </script>
 </body>
 </html>

????????我分了 0-2, 4-5, 7- 這三段 range。重新訪問一下,這時(shí)候報(bào)了一個(gè)跨域的錯(cuò)誤,說是發(fā)送預(yù)檢請求失敗。

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

瀏覽器發(fā)送預(yù)檢(preflight)請求

瀏覽器會(huì)在三種情況下發(fā)送預(yù)檢(preflight)請求:

  • ·用到了非 GET、POST 的請求方法,比如 PUT、DELETE 等,會(huì)發(fā)預(yù)檢請求看看服務(wù)端是否支持

  • ·用到了一些非常規(guī)請求頭,比如用到了 Content-Type,會(huì)發(fā)預(yù)檢請求看看服務(wù)端是否支持

  • ·用到了自定義 header,會(huì)發(fā)預(yù)檢請求

????????為啥 Range 頭單個(gè) range 不會(huì)觸發(fā)預(yù)檢請求,而多個(gè) range 就觸發(fā)了呢?因?yàn)槎鄠€(gè) range 的時(shí)候返回的 Content-Type 是不一樣的,是 multipart/byteranges 類型,比較特殊。預(yù)檢請求是 options 請求,那我們就支持一下:

 app.options('/', (req, res, next) => {
     res.setHeader('Access-Control-Allow-Origin', '*');
     res.setHeader('Access-Control-Allow-Headers', 'Range')
     res.end('');
 });

然后重新訪問:這時(shí)候你會(huì)發(fā)現(xiàn)雖然是 206 狀態(tài)碼,但返回的是整個(gè)內(nèi)容!

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

express 不支持多段 range

????????這是因?yàn)?express 只做了單 range 的支持,多段 range 可能它覺得沒必要支持吧。畢竟你發(fā)多個(gè)單 range 請求就能達(dá)到一樣的效果。MDN 官網(wǎng)的圖片是支持多 range 請求的,我們用那個(gè)看看:

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

multipart/** 搭配 boundary=**

????????請求 3 個(gè) range 的內(nèi)容??梢钥吹椒祷氐?Content-Type 確實(shí)是 multipart/byteranges,然后指定了 boundary 邊界線:

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

響應(yīng)內(nèi)容是這樣的:

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

????????以這些 boundary 分界線隔開的每一段內(nèi)容都包含 Content-Type、Content-Range 基于具體的那段 range 的內(nèi)容。這就是 multipart/byteranges 的格式,和我們常用的 multipart/form-data 很類似,只不過具體每段包含的 header 不同:

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

????????話說回來,其實(shí) express 只支持單段 range 問題也不大,不就是多發(fā)幾個(gè)請求就能達(dá)到一樣的效果。

分片下載功能

????????下面我們就用 range 來實(shí)現(xiàn)下文件的分片下載,最終合并成一個(gè)文件的功能。我們來下載一個(gè)圖片吧,分成兩塊下載,然后下載完合并起來。就用這個(gè)圖片好了:

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

 app.get('/', (req, res, next) => {
     res.setHeader('Access-Control-Allow-Origin', '*');
     res.download('guangguang.png', {
         acceptRanges: true
     })
 })

????????我們寫下分片下載的代碼,就分兩段:這個(gè)圖片是 626k,也就是 626000 字節(jié),那我們就分成 0-300000 和 300001- 兩段:

 <!DOCTYPE html>
 <html lang="en">
 <head>
     <script src="https://www.unpkg.com/axios@1.3.5/dist/axios.min.js"></script>
 </head>
 <body>
     <script>
         axios.get('http://localhost:3000', {
             headers: {
                 Range: 'bytes=0-300000',
             }
         }).then((res) => {
         }).catch((err) => {
             console.log(err);
         })

         axios.get('http://localhost:3000', {
             headers: {
                 Range: 'bytes=300001-',
             }
         }).then((res) => {
         }).catch((err) => {
             console.log(err);
         })
     </script>
 </body>
 </html>

試一下,兩個(gè)響應(yīng)分別是這樣的:

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

第一個(gè)響應(yīng)還能看到圖片的預(yù)覽,確實(shí)只有一部分:

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

“只讀的” ArrayBuffer 對象

然后我們要把兩段給拼起來,怎么拼呢?操作二進(jìn)制數(shù)據(jù)要用 JS 的 ArrayBuffer api 了:

ArrayBuffer
ArrayBuffer 對象用來表示通用的、固定長度的原始二進(jìn)制數(shù)據(jù)緩沖區(qū)。
它是一個(gè)字節(jié)數(shù)組,通常在其他語言中稱為 “byte array”。你不能直接操作 ArrayBuffer 中的內(nèi)容;而是要通過類型化數(shù)組對象或 DataView 對象來操作,它們會(huì)將緩沖區(qū)中的數(shù)據(jù)表示為特定的格式,并通過這些格式來讀寫緩沖區(qū)的內(nèi)容。

????????瀏覽器還有個(gè)特有的 Blob api 也是用于操作二進(jìn)制數(shù)據(jù)的。我們指定下響應(yīng)的類型為 arraybuffer:

 <!DOCTYPE html>
 <html lang="en">
 <head>
     <script src="https://www.unpkg.com/axios@1.3.5/dist/axios.min.js"></script>
 </head>
 <body>
     <script>
         const p1 = new Promise((resolve, reject) => {
             axios.get('http://localhost:3000', {
                 headers: {
                     Range: 'bytes=0-300000',
                 },
                 responseType: 'arraybuffer'
             }).then((res) => {
                 resolve(res.data)
             }).catch((err) => {
                 reject(err)
             })
         })

         const p2 = new Promise((resolve, reject) => {
             axios.get('http://localhost:3000', {
                 headers: {
                     Range: 'bytes=300001-',
                 },
                 responseType: 'arraybuffer'
             }).then((res) => {
                 resolve(res.data)
             }).catch((err) => {
                 reject(err)
             })
         })

         Promise.all([p1, p2]).then(res => {
             const [buffer1, buffer2] = res;
             console.log(buffer1, buffeer2)
         })
     </script>
 </body>
 </html>

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

DataView 子類?Uint8Array?操作二進(jìn)制數(shù)據(jù)

????????兩個(gè) ArrayBuffer 怎么合并呢?ArrayBuffer 本身只是存儲(chǔ)二進(jìn)制數(shù)據(jù)的,要操作二進(jìn)制數(shù)據(jù)要使用具體的 DataView 的子類。比如我們想以字節(jié)的方式操作,那就是 Uint8Array 的方式(Uint 是 unsigned integer,無符號整數(shù)):

 Promise.all([p1, p2]).then(res => {
     const [buffer1, buffer2] = res;

     const arr = new Uint8Array(buffer1.byteLength + buffer2.byteLength);

     const arr1 = new Uint8Array(buffer1);
     arr.set(arr1, 0);

     const arr2 = new Uint8Array(buffer2);
     arr.set(arr2, arr1.byteLength);

     console.log(arr.buffer)
 })

????????每個(gè) arraybuffer 都創(chuàng)建一個(gè)對應(yīng)的 Uint8Array 對象,然后創(chuàng)建一個(gè)長度為兩者之和的 Uint8Array 對象,把兩個(gè) Uint8Array 設(shè)置到不同位置。最后輸出合并的 Uint8Array 對象的 arraybuffer。這樣就完成了合并:

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

合并之后就是整個(gè)圖片了。那自然可以作為圖片展示,也可以下載。

我添加一個(gè) img 標(biāo)簽:

 <img id="img"/>

Blob + createObjectURL 創(chuàng)建 url

然后把 ArrayBuffer 轉(zhuǎn)成 Blob 設(shè)置以對象形式設(shè)置為 img 的 url

 const blob = new Blob([arr.buffer]);
 const url = URL.createObjectURL(blob);
 img.src =url;

現(xiàn)在就可以看到完整的圖片了:

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

現(xiàn)在我們就實(shí)現(xiàn)了文件的分片下載再合并!甚至,你還可以再做一步下載:

 const link = document.createElement('a');
 link.href = url;
 link.download = 'image.png';
 document.body.appendChild(link);
 link.click();
 link.addEventListener('click', () => {
     link.remove();
 });

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

全部代碼

現(xiàn)在的全部代碼如下:

 <!DOCTYPE html>
 <html lang="en">
 <head>
     <script src="https://www.unpkg.com/axios@1.3.5/dist/axios.min.js"></script>
 </head>
 <body>
     <img id="img"/>
     <script>
         const p1 = new Promise((resolve, reject) => {
             axios.get('http://localhost:3000', {
                 headers: {
                     Range: 'bytes=0-300000',
                 },
                 responseType: 'arraybuffer'
             }).then((res) => {
                 resolve(res.data)
             }).catch((err) => {
                 reject(err)
             })
         })

         const p2 = new Promise((resolve, reject) => {
             axios.get('http://localhost:3000', {
                 headers: {
                     Range: 'bytes=300001-',
                 },
                 responseType: 'arraybuffer'
             }).then((res) => {
                 resolve(res.data)
             }).catch((err) => {
                 reject(err)
             })
         })

         Promise.all([p1, p2]).then(res => {
             const [buffer1, buffer2] = res;

             const arr = new Uint8Array(buffer1.byteLength + buffer2.byteLength);

             const arr1 = new Uint8Array(buffer1);
             arr.set(arr1, 0);

             const arr2 = new Uint8Array(buffer2);
             arr.set(arr2, arr1.byteLength);

             const blob = new Blob([arr.buffer]);
             const url = URL.createObjectURL(blob);
             img.src = url;

             const link = document.createElement('a');
             link.href = url;
             link.download = 'image.jpg';
             document.body.appendChild(link);
             link.click();
             link.addEventListener('click', () => {
                 link.remove();
             });
         })
     </script>
 </body>
 </html>

通用的文件分片下載工具

拿到文件的大小 接口

????????當(dāng)然,一般不會(huì)這么寫死來用,我們可以封裝一個(gè)通用的文件分片下載工具。但分片之前需要拿到文件的大小,所以要增加一個(gè)接口:

 app.get('/length',(req, res, next) => {
     res.setHeader('Access-Control-Allow-Origin', '*');
     res.end('' + fs.statSync('./guangguang.png').size);
 })

請求這個(gè)接口,返回文件大?。?/p>

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

分片函數(shù)

然后我們來做分片:

 async function concurrencyDownload(path, size, chunkSize) {
     let chunkNum = Math.ceil(size / chunkSize);

     const downloadTask = [];
     for(let i = 1; i <= chunkNum; i++) {
         const rangeStart = chunkSize * (i - 1);
         const rangeEnd = chunkSize * i - 1;

         downloadTask.push(axios.get(path, {
             headers: {
                 Range: `bytes=${rangeStart}-${rangeEnd}`,
             },
             responseType: 'arraybuffer'
         }))
     }
     const arrayBuffers = await Promise.all(downloadTask.map(task => {
         return task.then(res => res.data)
     }))
     return mergeArrayBuffer(arrayBuffers);
 }

這部分代碼不難理解:

? ? ? ? ·首先根據(jù) chunk 大小來計(jì)算一共幾個(gè) chunk,通過 Math.ceil 向上取整。

? ? ? ? ·然后計(jì)算每個(gè) chunk 的 range,構(gòu)造下載任務(wù)的 promise。

? ? ? ? ·Promise.all 等待所有下載完成,之后合并 arraybuffer。

mergeArrayBuffer 函數(shù)

這里 arraybuffer 合并也封裝了一個(gè) mergeArrayBuffer 的方法:

 function  mergeArrayBuffer(arrays) {
     let totalLen = 0;
     for (let arr of arrays) {
         totalLen += arr.byteLength;
     }
     let res = new Uint8Array(totalLen)
     let offset = 0
     for (let arr of arrays) {
         let uint8Arr = new Uint8Array(arr)
         res.set(uint8Arr, offset)
         offset += arr.byteLength
     }
     return res.buffer
 }

????????就是計(jì)算總長度,創(chuàng)建一個(gè)大的 Uint8Array,然后把每個(gè) arraybuffer 轉(zhuǎn)成 Uint8Array 設(shè)置到對應(yīng)的位置,之后再轉(zhuǎn)為 arraybuffer 就好了。

我們來測試下:

 (async function() {
     const { data: len } = await axios.get('http://localhost:3000/length');
     const res = await concurrencyDownload('http://localhost:3000', len, 300000);
     console.log(res)

     const blob = new Blob([res]);
     const url = URL.createObjectURL(blob);
     img.src =url;
 })();

調(diào)用分片下載的方法,每 300000 字節(jié)分一片,應(yīng)該是可以分 3 片,我們看下結(jié)果:

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

確實(shí),3 個(gè) range 都對了,最后合并的結(jié)果也是對的:

基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!

至此,我們就實(shí)現(xiàn)了通用的分片下載功能!

全部代碼

全部前端代碼如下:

 <!DOCTYPE html>
 <html lang="en">
 <head>
     <script src="https://www.unpkg.com/axios@1.3.5/dist/axios.min.js"></script>
 </head>
 <body>
     <img id="img"/>
     <script>
         async function concurrencyDownload(path, size, chunkSize) {
             let chunkNum = Math.ceil(size / chunkSize);

             const downloadTask = [];
             for(let i = 1; i <= chunkNum; i++) {
                 const rangeStart = chunkSize * (i - 1);
                 const rangeEnd = chunkSize * i - 1;

                 downloadTask.push(axios.get(path, {
                     headers: {
                         Range: `bytes=${rangeStart}-${rangeEnd}`,
                     },
                     responseType: 'arraybuffer'
                 }))
             }
             const arrayBuffers = await Promise.all(downloadTask.map(task => {
                 return task.then(res => res.data)
             }))
             return mergeArrayBuffer(arrayBuffers);
         }

         function  mergeArrayBuffer(arrays) {
             let totalLen = 0;
             for (let arr of arrays) {
                 totalLen += arr.byteLength;
             }
             let res = new Uint8Array(totalLen)
             let offset = 0
             for (let arr of arrays) {
                 let uint8Arr = new Uint8Array(arr)
                 res.set(uint8Arr, offset)
                 offset += arr.byteLength
             }
             return res.buffer
         }

         (async function() {
             const { data: len } = await axios.get('http://localhost:3000/length');
             const res = await concurrencyDownload('http://localhost:3000', len, 300000);
             console.log(res)

             const blob = new Blob([res]);
             const url = URL.createObjectURL(blob);
             img.src =url;
         })();

     </script>
 </body>
 </html>

全部后端代碼如下:

 const express = require('express');
 const fs = require('fs');
 const app = express();

 app.get('/length',(req, res, next) => {
     res.setHeader('Access-Control-Allow-Origin', '*');
     res.end('' + fs.statSync('./guangguang.png').size);
 })

 app.options('/', (req, res, next) => {
     res.setHeader('Access-Control-Allow-Origin', '*');
     res.setHeader('Access-Control-Allow-Headers', 'Range')
     res.end('');
 });

 app.get('/', (req, res, next) => {
     res.setHeader('Access-Control-Allow-Origin', '*');
     res.download('guangguang.png', {
         acceptRanges: true
     })
 })

 app.listen(3000, () => {
     console.log(`server is running at port 3000`)
 })

總結(jié)

·文件下載是常見需求,只要設(shè)置 Content-Disposition 為 attachment 就可以。

·但大文件的時(shí)候,下載中斷了再重新傳體驗(yàn)不好,或者想實(shí)現(xiàn)分片下載再合并的功能,這時(shí)候就可以用 Range 了。

·在請求上帶上 Range 的范圍,如果服務(wù)器不支持,就會(huì)返回 200 加全部內(nèi)容。

·如果服務(wù)器支持 Range,會(huì)返回 206 的狀態(tài)碼和 Content-Range 的 header,表示這段內(nèi)容的范圍和全部內(nèi)容的總長度。

·如果 Range 超出了,會(huì)返回 416 的 狀態(tài)碼。

·多段 Range 的時(shí)候,會(huì)返回 multipart/byteranges 的格式,類似 multipart/form-data 一樣,都是通過 boundary 分割的,每一段都包含 Content-Range 和內(nèi)容。

·express 不支持多段 range,但我們可以通過發(fā)多個(gè)請求達(dá)到一樣的效果。

·我們基于 Range 實(shí)現(xiàn)了文件的分片下載,瀏覽器通過 ArrayBuffer 接收。

·ArrayBuffer 只讀,想要操作要通過 Uint8Array 來合并,之后再轉(zhuǎn)為 ArrayBuffer。

·這樣就可以通過 URL.createObjectURL 設(shè)置為 img 的 src 或者通過 a 標(biāo)簽的 download 屬性實(shí)現(xiàn)下載了。

·其實(shí)分片下載用的還是挺多的,比如看視頻的時(shí)候,是不是也是一段一段下載的呢?文章來源地址http://www.zghlxwxcb.cn/news/detail-498531.html

到了這里,關(guān)于基于 HTTP Range 實(shí)現(xiàn)文件分片并發(fā)下載!的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 使用Blazor WASM實(shí)現(xiàn)可取消的多文件帶校驗(yàn)并發(fā)分片上傳

    使用Blazor WASM實(shí)現(xiàn)可取消的多文件帶校驗(yàn)并發(fā)分片上傳

    上傳大文件時(shí),原始HTTP文件上傳功能可能會(huì)影響使用體驗(yàn),此時(shí)使用分片上傳功能可以有效避免原始上傳的弊端。由于分片上傳不是HTTP標(biāo)準(zhǔn)的一部分,所以只能自行開發(fā)相互配合的服務(wù)端和客戶端。文件分片上傳在許多情況時(shí)都擁有很多好處,除非已知需要上傳的文件一定

    2024年02月08日
    瀏覽(20)
  • React 實(shí)現(xiàn)文件分片上傳和下載

    文件分片上傳是一種將大文件分割成多個(gè)小片段進(jìn)行上傳的技術(shù)。它的原理是將大文件切割成固定大小的小塊,然后逐個(gè)上傳這些小塊,最后在服務(wù)器端將這些小塊合并成完整的文件。 文件分片上傳的機(jī)制可以提高上傳速度和穩(wěn)定性。由于大文件的上傳可能會(huì)受到網(wǎng)絡(luò)不穩(wěn)定

    2024年02月13日
    瀏覽(23)
  • 斷點(diǎn)續(xù)傳下載:深入理解 HTTP Header 中的 Range 和 Content-Range 參數(shù)

    [外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-bAhEY9hc-1687309020087)(https://example.com/resume-download-image)] 在進(jìn)行文件下載時(shí),我們經(jīng)常會(huì)遇到網(wǎng)絡(luò)不穩(wěn)定或其他中斷情況。為了提供更好的用戶體驗(yàn)和節(jié)省帶寬資源,斷點(diǎn)續(xù)傳技術(shù)應(yīng)運(yùn)而生。HTTP 協(xié)議通過

    2024年02月10日
    瀏覽(22)
  • 斷點(diǎn)續(xù)傳下載引出的http header的range和content-range參數(shù)

    最近同事在做安卓的斷點(diǎn)續(xù)傳下載,然后遇到了在請求頭添加RANGE參數(shù)設(shè)置時(shí): 網(wǎng)絡(luò)上找的資料都是設(shè)置contentLength,同時(shí)測試后,發(fā)現(xiàn)中間下載無法返回206成功,最終發(fā)現(xiàn)是需要end參數(shù)-1.此處稍微記錄一下,主要了解一下相關(guān)的知識。 HTTP1.1 協(xié)議(RFC2616)開始支持獲取文件的

    2024年02月10日
    瀏覽(27)
  • 【java】java實(shí)現(xiàn)大文件的分片上傳與下載(springboot+vue3)

    【java】java實(shí)現(xiàn)大文件的分片上傳與下載(springboot+vue3)

    源碼: https://gitee.com/gaode-8/big-file-upload 演示視頻 https://www.bilibili.com/video/BV1CA411f7np/?vd_source=1fe29350b37642fa583f709b9ae44b35 對于超大文件上傳我們可能遇到以下問題 ? 大文件直接上傳,占用過多內(nèi)存,可能導(dǎo)致內(nèi)存溢出甚至系統(tǒng)崩潰 ? 受網(wǎng)絡(luò)環(huán)境影響,可能導(dǎo)致傳輸中斷,只能重

    2024年02月02日
    瀏覽(29)
  • 基于element UI 實(shí)現(xiàn)大文件分片上傳

    將文件進(jìn)行切片,上傳至服務(wù)器,上傳完成后通知服務(wù)器進(jìn)行合并 屏幕錄制2022-11-11 16.40.06 測試用例 s-upload s-upload-img

    2024年02月01日
    瀏覽(25)
  • 使用Java實(shí)現(xiàn)遠(yuǎn)程文件下載到本地目錄

    今天開發(fā)時(shí)遇見了一個(gè)下載附件的需求,他的附件是存在一個(gè)網(wǎng)盤里查詢時(shí)只是給我返回了一個(gè)https的路徑,需要通過這個(gè)路徑把附件下載到本地的目錄里 這里我使用的是網(wǎng)上搜索的圖片路徑做了一下測試僅供參考 如正文介紹 使用Java實(shí)現(xiàn)遠(yuǎn)程文件下載到本地目錄記錄就到此

    2024年02月12日
    瀏覽(23)
  • Go源碼實(shí)現(xiàn)使用多線程并發(fā)下載大文件的功能

    摘要:Go語言編碼實(shí)現(xiàn)了使用多線程并發(fā)下載文件的功能。 1. 獲取系統(tǒng)的CPU核心數(shù)量,并將其作為線程數(shù)的參考值,并打印出來。 2. 定義要下載的文件的URL、線程數(shù)和輸出文件名。 3. 使用`getFileSize()`函數(shù)獲取文件大小,并打印出來。 4. 根據(jù)文件大小和線程數(shù)計(jì)算文件塊大小

    2024年02月08日
    瀏覽(28)
  • 基于curl 使用http多線程下載大文件

    如需完整代碼,可評論區(qū)留言

    2024年02月04日
    瀏覽(28)
  • 【前端面試】中大文件上傳/下載:中等文件代理服務(wù)器放行+大文件切片傳輸+并發(fā)請求+localstorage實(shí)現(xiàn)斷點(diǎn)續(xù)傳

    【前端面試】中大文件上傳/下載:中等文件代理服務(wù)器放行+大文件切片傳輸+并發(fā)請求+localstorage實(shí)現(xiàn)斷點(diǎn)續(xù)傳

    目錄 切片上傳~spark-md5 原理:流式計(jì)算+分塊處理 文件標(biāo)識spark-md5:A-B A.切片哈希值合并 B.首尾切片+其他切片前中后各取2M 計(jì)算hash:A-B(參考React的Fiber架構(gòu)) A.線程:web-worker B.空閑:requestIdleCallback 異步并發(fā)控制:A-B(參考http2的多路復(fù)用) A.promise.allSettled() B.并發(fā)數(shù)max=

    2024年02月12日
    瀏覽(30)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包