开发者社区> 问答> 正文

断点续传 是否有时间限制?

网络断开时间过长,断点续传则不能实现

展开
收起
游客p4cqsnkw6wszu 2020-10-22 15:15:55 600 0
1 条回答
写回答
取消 提交回答
  • 有时候下载文件下载到一半的时候网络断开了, 需要继续下载的时候, 如果不支持断点, 用户需要重新下载, 如果支持 range, 客户端会记录已经下载的内容,当网络恢复时, 则向服务端发送剩下 range 的读取请求, 服务端接收到请求后,会根据 range 找到剩下的内容 发送给 客户端。

    客户端也可以通过 curl -v --header 'Range: bytes=xx-xx' http://localhost:3000 来指定资源的 byte 范围, 但是具体怎么返回还是服务端说的算, 从什么位置开始返回 也是服务端说的算 可以是 0 也可以是 100 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 客户端 通过 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);

    2021-02-13 23:02:36
    赞同 展开评论 打赏
问答地址:
问答排行榜
最热
最新

相关电子书

更多
低代码开发师(初级)实战教程 立即下载
冬季实战营第三期:MySQL数据库进阶实战 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载