真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

怎么在NodeJS中利用Range請求實現(xiàn)一個下載功能

怎么在NodeJS中利用Range請求實現(xiàn)一個下載功能?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

為連云港等地區(qū)用戶提供了全套網(wǎng)頁設計制作服務,及連云港網(wǎng)站建設行業(yè)解決方案。主營業(yè)務為成都網(wǎng)站建設、做網(wǎng)站、連云港網(wǎng)站設計,以傳統(tǒng)方式定制建設網(wǎng)站,并提供域名空間備案等一條龍服務,秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務。我們深信只要達到每一位用戶的要求,就會得到認可,從而選擇與我們長期合作。這樣,我們也可以走得更遠!

服務端的實現(xiàn)

通過 http 模塊創(chuàng)建服務器處理 Range 請求,在服務器代碼中我們?yōu)榱藴p少回調(diào)嵌套使用 async 函數(shù),所以需要將異步的操作方法轉(zhuǎn)換成 Promise,以往我們使用 util 的 promisify 來一個一個轉(zhuǎn)換異步方法,比較麻煩,我們這次使用第三方模塊 mz 并直接引入轉(zhuǎn)換好的替代模塊。

使用 mz 之前需要先安裝:

npm install mz

服務端代碼如下:

// 文件:server.js
const http = require("http");
const path = require("path");
const url = require("url");

// 引入 mz 模塊轉(zhuǎn)換成 Promise 的 fs 模塊
const fs = require("mz/fs");

// 請求處理函數(shù)
async function listener(req, res) {
  // 獲取 range 請求頭,格式為 Range:bytes=0-5
  let range = req.headers["range"];

  // 下載文件路徑
  let p = path.resovle(__dirname, url.parse(url, true).pathname);

  // 存在 range 請求頭將返回范圍請求的數(shù)據(jù)
  if (range) {
    // 獲取范圍請求的開始和結(jié)束位置
    let [, start, end] = range.match(/(\d*)-(\d*)/);

    // 錯誤處理
    try {
      let statObj = await fs.stat(p);
    } catch (e) {
      res.end("Not Found");
    }

    // 文件總字節(jié)數(shù)
    let total = statObj.size;

    // 處理請求頭中范圍參數(shù)不傳的問題
    start = start ? ParseInt(start) : 0;
    end = end ? ParseInt(end) : total - 1;

    // 響應客戶端
    res.statusCode = 206;
    res.setHeader("Accept-Ranges", "bytes");
    res.setHeader("Content-Range", `bytes ${start}-${end}/${total}`);
    fs.createReadStream(p, { start, end }).pipe(res);
  } else {
    // 沒有 range 請求頭時將整個文件內(nèi)容返回給客戶端
    fs.createReadStream(p).pipe(res);
  }
}

// 創(chuàng)建服務器
const server = http.createServer(listener);

// 監(jiān)聽端口
server.listen(3000, () => {
  console.log("server start 3000");
});

在上面服務端的代碼中,需要兼容 Range 請求和普通請求,兩種請求的區(qū)別是,如果客戶端發(fā)送的是 Range 請求,會攜帶 Range:bytes=0-5 格式的請求頭,我們可以通過 req 的 headers 屬性獲取,在獲取請求頭時,原本大寫字母開頭 NodeJS 統(tǒng)一處理成小寫,所以獲取時應小寫。

如果是 Range 請求則通過可讀流讀取對應的內(nèi)容返回客戶端,如果不是,則通過可讀流讀取整個文件返回客戶端,在響應 Range 請求的過程中需要設置響應狀態(tài)為 206,需要設置響應頭 Accept-Ranges 值為 bytes,需要設置響應頭 Content-Range 值為 byte 0-5/100 的格式,0 為返回數(shù)據(jù)開始的索引,5 為結(jié)束的索引(包含),100 為文件的總字節(jié)數(shù)。

在通過 url 和 path 模塊解析和拼接下載文件路徑時,應該進行錯誤檢測,如果文件不存在則直接返回客戶端 Not Found。

我們可以使用 curl 命令來檢測我們的服務端代碼,在命令行工具中輸入下面命令,在命令窗口查看返回值是否正確。

curl -v --header "Range:bytes=0-5" http://localhost:3000

客戶端的實現(xiàn)

在上面使用 curl 命令來訪問我們的服務器時,只能請求固定范圍的數(shù)據(jù),而不是類似于下載功能,每次都下載一個范圍的數(shù)據(jù),但是想要多次下載并自動維護 Range 的范圍需要借助我們自己實現(xiàn)的客戶端邏輯。

為了簡便,我們的下載客戶端是在命令行窗口運行的,通過指令來模擬實際項目中的開始下載、暫停和恢復按鈕,當在窗口中輸入 s 指令時開始下載,輸入 p 指令時暫停下載,輸入 r 指令時恢復下載。

// 文件:client.js
const http = require("http");
const fs = require("fs");
const path = require("path");

// 請求配置
let config = {
  host: "localhost",
  port: 3000,
  path: "/download.txt"
};

let start = 0; // 請求初始值
let step = 5; // 每次請求字符個數(shù)
let pause = false; // 暫停狀態(tài)
let total; // 文件總長度

// 創(chuàng)建可寫流
let ws = fs.createWriteStream(path.resolve(__dirname, config.path.slice(1)));

// 下載函數(shù)
function download() {
  // 配置,每次范圍請求 step 個字節(jié)
  config.headers = {
    "Range": `bytes=${start}-${start + step - 1}`;
  };

  // 維護下次 start 的值
  start += step;

  // 發(fā)送請求
  http.request(config, res => {
    // 獲取文件總長度
    if (typeof total !== "number") {
      total = res.headers["content-ranges"].match(/\/(\d*)/)[1];

    }

    // 讀取返回數(shù)據(jù)
    let buffers = [];
    res.on("data", data => buffers.push(data));
    res.on("end", () => {
      // 合并數(shù)據(jù)并寫入文件
      let buf = Buffer.concat(buffers);
      ws.write(buf);

      // 遞歸進行下一次請求
      if (!pause && start < total) {
        download();
      }
    });
  }).end();
}

// 監(jiān)控輸入
process.stdin.on("data", data => {
  // 獲取指令
  let ins = data.toString().match(/(\w*)\/r/)[1];
  switch (ins) {
    case "s":
    case "r":
      pause = false;
      download();
      break;
    case "p":
      pause = true;
      break;
  }
});

在上面代碼中下載的文件通過 config 中的 path 屬性配置,每次調(diào)用 download 函數(shù)下載時都會重新計算當前范圍請求的初始位置和結(jié)束位置,并設置 Range 請求頭,下一次請求靠遞歸 download 來實現(xiàn)。

在執(zhí)行時需先啟動我們的服務器,在通過命令行輸入 node client.js 來啟動客戶端,在命令窗口輸入對應的指令進行開始下載、暫停下載和恢復下載操作。

關(guān)于怎么在NodeJS中利用Range請求實現(xiàn)一個下載功能問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識。


本文題目:怎么在NodeJS中利用Range請求實現(xiàn)一個下載功能
當前URL:http://weahome.cn/article/jpcjgo.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部