断点续传了解一下

Range 断点续传

有时候下载文件下载到一半的时候网络断开了, 需要继续下载的时候, 如果不支持断点, 用户需要重新下载, 如果支持 range, 客户端会记录已经下载的内容,当网络恢复时, 则向服务端发送剩下 range 的读取请求, 服务端接收到请求后,会根据 range 找到剩下的内容 发送给 客户端。

  1. 客户端也可以通过 curl -v --header 'Range: bytes=xx-xx' http://localhost:3000 来指定资源的 byte 范围, 但是具体怎么返回还是服务端说的算, 从什么位置开始返回 也是服务端说的算 可以是 0 也可以是 100
  2. server 通过请求头获取 Range: bytes=xx-xx 来判断是否支持 range , 如果这个值存在 且 有效,通过
    res.setHeader('Accept-Ranges','bytes');res.setHeader('Content-Range','${start}-${end}/${total}') 告知客户端支持 range , 每次发送内容的 bytes 范围, 并将对应的内容发送给 客户端 ,响应的状态码变成 206,表示 Partial Content,并设置 Content-Range。如果无效,则返回 416 状态码,表明 Request Range Not
  3. 客户端 通过 response.headers['content-range'] 可以获取 range 范围 及 总数, 以便客户端知道什么时候该结束请求
**客户端代码**

let options = {
    hostname: 'localhost',
    port: 3000,
    path: '/',
    method: 'GET'
};

let fs = require('fs');
let path = require('path');
let http = require('http');
let ws = fs.createWriteStream('./download.txt');
let pause = false; // 是否暂停
let start = 0; // 开始位置

// 下载 = 每次获取 10 个下载
process.stdin.on('data', function (chunk) {
    chunk = chunk.toString();
    if (chunk.includes('p')) {
        // 断开下载
        pause = true;
    } else {
        // 继续下载
        pause = false;
        download();
    }
});

function download () {
    options.headers = {
        Range: `bytes=${start}-${start + 10}`
    }
    start += 10;
    // 发送请求
    http.get(options, function (res) {
        let range = res.headers['content-range'];
        let total = range.split('/')[1];
        let buffers = [];
        res.on('data', function (chunk) {
            buffers.push(chunk);
        });
        res.on('end', function () {
            ws.write(Buffer.concat(buffers)); // 将 buffers 转为字符串写入到文件中
            setTimeout(function () {
                if (pause === false && start < total) {
                    download();
                }
            }, 1000)
        })
    })
}

download();



**服务端**

let http = require('http');
let fs = require('fs');
let path = require('path');
let { promisify } = require('util');
let stat = promisify(fs.stat);

/**
 * 客户端会发送一个头 Range: bytes=0-10
 * 服务端返回一个头
 *      Accept-Ranges: bytes
 *      Content-Range: 0-10/总大小
 */
let serevr = http.createServer(async function (req, res) {
    let p = path.join(__dirname, './content.txt');
    let statObj = await stat(p);
    let start = 0;
    let end = statObj.size - 1; // 读流是包前又包后的
    let total = end;
    let range = req.headers['range'];

    if (range) {
        res.setHeader('Accept-Ranges', 'bytes');
        let result = range.match(/bytes=(\d*)-(\d*)/);
        start = result[1] ? parseInt(result[1]) : start;
        end = result[2] ? parseInt(result[2]) - 1 : end; // 因为流的 end 是 包前又包后的 此次这个地方需要减去 1 

        // 告知客户端获取成功
        res.setHeader('Content-Range', `${start}-${end}/${total}`);
    }
    res.setHeader('Content-Type', 'text/plain;charset=utf8');
    fs.createReadStream(p, { start, end }).pipe(res);
});
serevr.listen(3000); 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值