国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

node實現(xiàn)分片下載的示例代碼

2019-11-19 12:41:22
字體:
來源:轉載
供稿:網(wǎng)友

本文基于http Range Requests協(xié)議,實現(xiàn)了分片下載的功能。

使用場景包括基于瀏覽器的流文件片段傳輸、基于客戶端的分片下載等。

原理

http通過Range Requests相關的header,可以與服務器進行協(xié)商,實現(xiàn)分部分的請求。

這里就不細說具體協(xié)議內容了,具體可以參考這兩篇文章,解釋的非常詳細:

  1. https://tools.ietf.org/html/rfc7233
  2. http://www.survivalescaperooms.com/article/68284.htm

下面貼一下實現(xiàn)過程。

服務端代碼

服務端用node實現(xiàn):

app.use(async ctx => { const file = path.join(__dirname, `${PATH}${ctx.path}`); // 1、404檢查 try {  fs.accessSync(file); } catch (e) {  return ctx.response.status = 404; } const method = ctx.request.method; const { size } = fs.statSync(file); // 2、響應head請求,返回文件大小 if ('HEAD' == method) {  return ctx.set('Content-Length', size); } const range = ctx.headers['range']; // 3、通知瀏覽器可以進行分部分請求 if (!range) {  return ctx.set('Accept-Ranges', 'bytes'); } const { start, end } = getRange(range); // 4、檢查請求范圍 if (start >= size || end >= size) {  ctx.response.status = 416;  return ctx.set('Content-Range', `bytes */${size}`); } // 5、206分部分響應 ctx.response.status = 206; ctx.set('Accept-Ranges', 'bytes'); ctx.set('Content-Range', `bytes ${start}-${end ? end : size - 1}/${size}`); ctx.body = fs.createReadStream(file, { start, end });});app.listen(3000, () => console.log('partial content server start'));function getRange(range) { var match = /bytes=([0-9]*)-([0-9]*)/.exec(range); const requestRange = {}; if (match) {  if (match[1]) requestRange.start = Number(match[1]);  if (match[2]) requestRange.end = Number(match[2]); } return requestRange;}

代碼實現(xiàn)的功能邏輯大致是:

  • 對請求的資源做檢查,不存在則響應404
  • 對于HEAD請求,返回資源大小
  • 如果GET請求沒有告知range,返回Content-Length,告知瀏覽器可以進行分片請求
  • 如果請求設置了range,則檢查range是否合法,不合法返回合法的rangge
  • 一切正常,獲取文件range范圍部分,做流響應

代碼很簡單,把Range Requests協(xié)議對應實現(xiàn)一遍就ok了,當然這里沒有完全實現(xiàn)協(xié)議的內容,但已經(jīng)滿足了這里演示的需求。

服務端代碼ok了,用一個瀏覽器的demo來檢驗一下。

瀏覽器例子

現(xiàn)代瀏覽器基本都實現(xiàn)了Range Requests,這里用audio標簽作為例子。

<html> <head>  <title>分片流傳輸</title>  <script type="text/javascript">   function jump() {    const player = document.getElementById('musicPlayer');    // 從30s開始播放    player.currentTime = 30;   }  </script> </head> <body>  <audio id="musicPlayer" src="http:127.0.0.1:3000/source.mp3" controls></audio>  <button onclick="jump()">切到30s</button> </body></html>

最終的效果是這樣的:


對比兩張圖,當html加載完成,瀏覽器自動請求資源,此時header有Range: bytes=0-,表示從第0 byte開始加載資源;當點擊跳到30s處播放時,此時header變成了Range: bytes=3145728-

同樣用這個服務端代碼,還可以實現(xiàn)一個客戶端,模擬一下分包下載。

node分包下載

這個例子演示了,對一個資源,并發(fā)的實現(xiàn)分部分的下載,然后再合并成一個文件。

這里也是用node實現(xiàn):

import request from 'request';import path from 'path';import fs from 'fs';const SINGLE = 1024 * 1000;const SOURCE = 'http://127.0.0.1:3000/source.mp3';request({ method: 'HEAD', uri: SOURCE,}, (err, res) => { if (err) return console.error(err); const file = path.join(__dirname, './download/source.mp3'); try {  fs.closeSync(fs.openSync(file, 'w')); } catch (err) {  return console.error(err); } const size = Number(res.headers['content-length']); const length = parseInt(size / SINGLE); for (let i=0; i<length; i++) {  let start = i * SINGLE;  let end = i == length ? (i + 1) * SINGLE - 1 : size - 1;  request({   method: 'GET',   uri: SOURCE,   headers: {    'range': `bytes=${start}-${end}`   },  }).on('response', (resp) => {   const range = resp.headers['content-range'];   const match = /bytes ([0-9]*)-([0-9]*)/.exec(range);   start = match[1];   end = match[2];  }).pipe(fs.createWriteStream(file, {start, end})); }});

代碼比較簡單,就是開啟多個http請求,并發(fā)的下載資源,然后根據(jù)響應的content-range,寫到文件的對應位置。

參考文章:

https://tools.ietf.org/html/rfc7233
http://www.survivalescaperooms.com/article/68284.htm

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網(wǎng)。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 富民县| 沙坪坝区| 页游| 育儿| 石家庄市| 和田县| 西青区| 永川市| 滦南县| 呈贡县| 武邑县| 江源县| 莱州市| 三穗县| 钟山县| 尉氏县| 英德市| 德保县| 武安市| 蕲春县| 巴里| 大城县| 阿图什市| 望谟县| 玛沁县| 乌拉特后旗| 海门市| 乐亭县| 南宁市| 获嘉县| 樟树市| 大田县| 潍坊市| 教育| 蕲春县| 读书| 黑河市| 江安县| 定边县| 霸州市| 色达县|