<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問(wèn)答1問(wèn)答10問(wèn)答100問(wèn)答1000問(wèn)答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問(wèn)答文章1 問(wèn)答文章501 問(wèn)答文章1001 問(wèn)答文章1501 問(wèn)答文章2001 問(wèn)答文章2501 問(wèn)答文章3001 問(wèn)答文章3501 問(wèn)答文章4001 問(wèn)答文章4501 問(wèn)答文章5001 問(wèn)答文章5501 問(wèn)答文章6001 問(wèn)答文章6501 問(wèn)答文章7001 問(wèn)答文章7501 問(wèn)答文章8001 問(wèn)答文章8501 問(wèn)答文章9001 問(wèn)答文章9501
        當(dāng)前位置: 首頁(yè) - 科技 - 知識(shí)百科 - 正文

        NodeJS使用Range請(qǐng)求實(shí)現(xiàn)下載功能的方法示例

        來(lái)源:懂視網(wǎng) 責(zé)編:小采 時(shí)間:2020-11-27 22:06:24
        文檔

        NodeJS使用Range請(qǐng)求實(shí)現(xiàn)下載功能的方法示例

        NodeJS使用Range請(qǐng)求實(shí)現(xiàn)下載功能的方法示例:前言 本篇使用 NodeJS 的 HTTP 服務(wù)創(chuàng)建客戶端,使用 Range 請(qǐng)求實(shí)現(xiàn)下載功能,并通過(guò)本篇的 Demo 擴(kuò)展在業(yè)務(wù)中實(shí)現(xiàn)斷點(diǎn)續(xù)傳等功能的思路。 服務(wù)端的實(shí)現(xiàn) 我們通過(guò) http 模塊創(chuàng)建服務(wù)器處理 Range 請(qǐng)求,在服務(wù)器代碼中我們?yōu)榱藴p少回調(diào)嵌套使用 asyn
        推薦度:
        導(dǎo)讀NodeJS使用Range請(qǐng)求實(shí)現(xiàn)下載功能的方法示例:前言 本篇使用 NodeJS 的 HTTP 服務(wù)創(chuàng)建客戶端,使用 Range 請(qǐng)求實(shí)現(xiàn)下載功能,并通過(guò)本篇的 Demo 擴(kuò)展在業(yè)務(wù)中實(shí)現(xiàn)斷點(diǎn)續(xù)傳等功能的思路。 服務(wù)端的實(shí)現(xiàn) 我們通過(guò) http 模塊創(chuàng)建服務(wù)器處理 Range 請(qǐng)求,在服務(wù)器代碼中我們?yōu)榱藴p少回調(diào)嵌套使用 asyn

        前言

        本篇使用 NodeJS 的 HTTP 服務(wù)創(chuàng)建客戶端,使用 Range 請(qǐng)求實(shí)現(xiàn)下載功能,并通過(guò)本篇的 Demo 擴(kuò)展在業(yè)務(wù)中實(shí)現(xiàn)斷點(diǎn)續(xù)傳等功能的思路。

        服務(wù)端的實(shí)現(xiàn)

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

        使用 mz 之前需要先安裝:

        npm install mz

        服務(wù)端代碼如下:

        // 文件:server.js
        const http = require("http");
        const path = require("path");
        const url = require("url");
        
        // 引入 mz 模塊轉(zhuǎn)換成 Promise 的 fs 模塊
        const fs = require("mz/fs");
        
        // 請(qǐng)求處理函數(shù)
        async function listener(req, res) {
         // 獲取 range 請(qǐng)求頭,格式為 Range:bytes=0-5
         let range = req.headers["range"];
        
         // 下載文件路徑
         let p = path.resovle(__dirname, url.parse(url, true).pathname);
        
         // 存在 range 請(qǐng)求頭將返回范圍請(qǐng)求的數(shù)據(jù)
         if (range) {
         // 獲取范圍請(qǐng)求的開(kāi)始和結(jié)束位置
         let [, start, end] = range.match(/(\d*)-(\d*)/);
        
         // 錯(cuò)誤處理
         try {
         let statObj = await fs.stat(p);
         } catch (e) {
         res.end("Not Found");
         }
        
         // 文件總字節(jié)數(shù)
         let total = statObj.size;
        
         // 處理請(qǐng)求頭中范圍參數(shù)不傳的問(wèn)題
         start = start ? ParseInt(start) : 0;
         end = end ? ParseInt(end) : total - 1;
        
         // 響應(yīng)客戶端
         res.statusCode = 206;
         res.setHeader("Accept-Ranges", "bytes");
         res.setHeader("Content-Range", `bytes ${start}-${end}/${total}`);
         fs.createReadStream(p, { start, end }).pipe(res);
         } else {
         // 沒(méi)有 range 請(qǐng)求頭時(shí)將整個(gè)文件內(nèi)容返回給客戶端
         fs.createReadStream(p).pipe(res);
         }
        }
        
        // 創(chuàng)建服務(wù)器
        const server = http.createServer(listener);
        
        // 監(jiān)聽(tīng)端口
        server.listen(3000, () => {
         console.log("server start 3000");
        });
        
        

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

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

        在通過(guò) url 和 path 模塊解析和拼接下載文件路徑時(shí),應(yīng)該進(jìn)行錯(cuò)誤檢測(cè),如果文件不存在則直接返回客戶端 Not Found。

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

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

        客戶端的實(shí)現(xiàn)

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

        為了簡(jiǎn)便,我們的下載客戶端是在命令行窗口運(yùn)行的,通過(guò)指令來(lái)模擬實(shí)際項(xiàng)目中的開(kāi)始下載、暫停和恢復(fù)按鈕,當(dāng)在窗口中輸入 s 指令時(shí)開(kāi)始下載,輸入 p 指令時(shí)暫停下載,輸入 r 指令時(shí)恢復(fù)下載。

        // 文件:client.js
        const http = require("http");
        const fs = require("fs");
        const path = require("path");
        
        // 請(qǐng)求配置
        let config = {
         host: "localhost",
         port: 3000,
         path: "/download.txt"
        };
        
        let start = 0; // 請(qǐng)求初始值
        let step = 5; // 每次請(qǐng)求字符個(gè)數(shù)
        let pause = false; // 暫停狀態(tài)
        let total; // 文件總長(zhǎng)度
        
        // 創(chuàng)建可寫流
        let ws = fs.createWriteStream(path.resolve(__dirname, config.path.slice(1)));
        
        // 下載函數(shù)
        function download() {
         // 配置,每次范圍請(qǐng)求 step 個(gè)字節(jié)
         config.headers = {
         "Range": `bytes=${start}-${start + step - 1}`;
         };
        
         // 維護(hù)下次 start 的值
         start += step;
        
         // 發(fā)送請(qǐng)求
         http.request(config, res => {
         // 獲取文件總長(zhǎng)度
         if (typeof total !== "number") {
         total = res.headers["content-ranges"].match(/\/(\d*)/)[1];
        
         }
        
         // 讀取返回?cái)?shù)據(jù)
         let buffers = [];
         res.on("data", data => buffers.push(data));
         res.on("end", () => {
         // 合并數(shù)據(jù)并寫入文件
         let buf = Buffer.concat(buffers);
         ws.write(buf);
        
         // 遞歸進(jìn)行下一次請(qǐng)求
         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;
         }
        });

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

        在執(zhí)行時(shí)需先啟動(dòng)我們的服務(wù)器,在通過(guò)命令行輸入 node client.js 來(lái)啟動(dòng)客戶端,在命令窗口輸入對(duì)應(yīng)的指令進(jìn)行開(kāi)始下載、暫停下載和恢復(fù)下載操作。

        總結(jié)

        相信現(xiàn)在已經(jīng)了解什么是范圍請(qǐng)求,范圍請(qǐng)求客戶端和服務(wù)端需要做些什么,其實(shí)說(shuō)白了就是對(duì)應(yīng)的請(qǐng)求頭和響應(yīng)頭的使用,需要注意的是范圍請(qǐng)求的響應(yīng)狀態(tài)碼為 206,這樣的需求在一些上傳、下載資源的網(wǎng)站也很常見(jiàn),其目的就是為了讓我們實(shí)現(xiàn)斷點(diǎn)續(xù)傳,不至于一次沒(méi)有上傳或下載完成的資源文件,在下一次的做同樣操作時(shí)需要重新來(lái)過(guò),可以接著上次的位置繼續(xù),范圍請(qǐng)求在視頻網(wǎng)站上也廣泛應(yīng)用,邊請(qǐng)求邊觀看,不至于一次加載整個(gè)視頻資源,節(jié)省流量,節(jié)省時(shí)間。

        聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        NodeJS使用Range請(qǐng)求實(shí)現(xiàn)下載功能的方法示例

        NodeJS使用Range請(qǐng)求實(shí)現(xiàn)下載功能的方法示例:前言 本篇使用 NodeJS 的 HTTP 服務(wù)創(chuàng)建客戶端,使用 Range 請(qǐng)求實(shí)現(xiàn)下載功能,并通過(guò)本篇的 Demo 擴(kuò)展在業(yè)務(wù)中實(shí)現(xiàn)斷點(diǎn)續(xù)傳等功能的思路。 服務(wù)端的實(shí)現(xiàn) 我們通過(guò) http 模塊創(chuàng)建服務(wù)器處理 Range 請(qǐng)求,在服務(wù)器代碼中我們?yōu)榱藴p少回調(diào)嵌套使用 asyn
        推薦度:
        標(biāo)簽: 下載 請(qǐng)求 js
        • 熱門焦點(diǎn)

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 国产在线观看片a免费观看| 久久精品国产免费| 青草草在线视频永久免费| 亚洲熟妇少妇任你躁在线观看| 91青青青国产在观免费影视| 日木av无码专区亚洲av毛片| 成全高清在线观看免费| 亚洲AV无码第一区二区三区| 未满十八18禁止免费无码网站| 亚洲精品自产拍在线观看动漫| 人人揉揉香蕉大免费不卡| 亚洲综合视频在线| 在线观看免费高清视频| 麻豆亚洲AV成人无码久久精品| 四虎国产精品免费久久| 国产亚洲精aa在线看| 四虎影院永久免费观看| 丰满妇女做a级毛片免费观看| 亚洲中文字幕在线第六区| 免费精品无码AV片在线观看| 亚洲视频一区在线播放| 卡1卡2卡3卡4卡5免费视频| 一级做a爱过程免费视| 亚洲国产一二三精品无码| 免费看男女下面日出水来| 国产成人高清亚洲一区久久| 亚洲伊人成无码综合网| 99久久免费观看| 亚洲AV无码国产剧情| 亚洲啪啪AV无码片| 成人女人A级毛片免费软件| 婷婷国产偷v国产偷v亚洲| 国产亚洲精品久久久久秋霞| 在线看片v免费观看视频777| 麻豆91免费视频| 亚洲欧洲另类春色校园小说| 亚洲av无码国产精品色在线看不卡 | 亚洲色成人四虎在线观看| 亚洲精品线路一在线观看| 曰批全过程免费视频在线观看无码 | 一级黄色毛片免费看|