首页 > 其他分享 >#yyds干货盘点#web端断点续传的思路

#yyds干货盘点#web端断点续传的思路

时间:2023-04-22 19:05:34浏览次数:38  
标签:yyds code const web index 断点续传 res hash 上传

讲断点续传前,咱们先讲讲大文件上传。大文件上传,可能会出现,上传时间过长,接口限制了文件大小。所以,大文件直接上传,也很不友好,一般采用分片上传的方式去上传。而blob提供了slice方法, file继承了blob自然也能使用slice去进行分片处理。

处理流程:

  • 前端对大文件进行分片,分片名采用文件hash后续会讲下标
  • 为了防止完全占用tcp资源,我这里是采用4个4个上传
  • 在最后,再发送一个合并请求
  • 服务端根据请求,对前面的分片内容进行合并成一个整体文件,然后删除分片
const handleUpload = () => {
    chunks = [];

    const file: File = files.current[dataIndex];
    // 获取对应文件file
    let start = 0, end = BIG_FILE_SIZE;
    
    // const BIG_FILE_SIZE = 1024 * 1024 * 2;
    while(true) {
        const part: Blob = file.slice(start, end);
        if (part.size) {
            chunks.push(part);
        } else {
            break;
        }
        start += BIG_FILE_SIZE;
        end += BIG_FILE_SIZE;
    };
    
    // worker!.postMessage({ chunkList: chunks });
    // 利用webworker获取hash,后面会讲
    return;
};
const partUpload = async (start: number) => {
    const uploadArr = [];
    let restReq = MAX_FILE_TCP;
    // MAX_FILE_TCP = 4;同时发起4个连接
    let index = start;
    while (restReq) {
        if (index >= chunkCount) {
        // chunkCount是chunk的length,即多少个片段
            break;
        };
        
        // const blobPart = `${hash}-${index}`;
        // if (hashData[hash] && hashData[hash][blobPart]) 
        // {
        //     index++;
        //     continue;
        // };
        // 注释部分是,断点续传部分代码,可跳过
        
        const formData = new FormData();
        formData.append('file', chunks[index]);
        formData.append('xx', xx);
        
        const uploadFunc = () => {
            return new Promise(async (res) => {
                const { code } = await uploadPart(formData);
                res(code);
            });
        };
        
        uploadArr.push(uploadFunc);
        index++;
        restReq--;
    };
    const result = await Promise.all(uploadArr.map(v => v()));
    
    result.map((v) => {
      if (v === 0) {
        console.log('上传片段成功');
      } else {
        throw new Error('上传失败');
      }
      return null;
    });
    
    if (index < chunkCount) {
      partUpload(index);
    } else {
        const params = {
            // sth.
        };
        const {code} = await partMerge(params);
        // 发送合并请求
        // todo code sth.
    }
};

服务端的话,我这边是把文件根据对应的hash和下标进行命名,即static/hash/hash-i。利用fs.rename去修改文件&路径, 通过pipe合并文件。

router.post('/upload_part', (req, res) => {
    try {
        const { hash, index } = req.body;
        const { file } = req;
        const sourcePath = path.join(__dirname, file.path);
        const destPath = path.join(__dirname, `xxxx/${hash}/${hash}-${index}`);
        fs.renameSync(sourcePath, destPath);
        return res.json({code: 0});
    } catch(e) {
        return res.json({code: 1, msg: e});
    }
});

router.post('/merge_part', (req, res) => {
    try {
        const destPath = 'xxx/yyy/zzz/a.png';
        const writePath = fs.createWriteStream(destPath);
        // 最终合并结果存储在哪
        const fileMerge = (i: number) => {
            const blobPath = `xxx/part/${hash}/${hash}-${i}`;
            const blobFile = fs.createReadStream(blobPath);
            blobFile.on("end", async (err) => {
                if (err) {
                    return res.json({code: 1, msg: err});
                };
                fs.unlink(blobPath);
                // 删除片段
                if (i + 1 < chunkCount) {
                    fileMerge(i + 1);
                } else {
                    fs.rmdirSync(`xxx/part/${hash}`);
                    // 删除文件夹
                    // 数据库操作 todo
                    return res.json({ code: 0 });
                }
            });
            blobFile.pipe(writeStream, { end: false });
        };
        fileMerge(0);
    } catch(e) {
        return res.json({code: 1, msg: e});
    }
});

断点续传

大文件分片上传,如果客户端发生异常中断了上传过程,那么下次重新上传的时候,比较友好的做法应该是跳过那些已经上传的片段。 那么问题也就是,怎么跳过那些文件?刚才前面的代码,也显示了,其实就是通过${hash}-${i}设置文件名,然后保存已经上传成功的片段数据,在文件分片上传的时候,跳过已经上传过的片段,就是断点续传辽。 对于这类数据存储,一般都是两个方法:

  • 前端存储
  • 服务端存储

前端存储的话,一般就是用localStorage,不太推荐使用。因为用户如果清了缓存,或者换了设备登陆,就无法生效。

服务端的话,就返回对应的已成功上传的片段名。因为对应userId下的文件hash-i,是唯一的。node这里就采用readdirSync/readdir去读取文件名辽。

前端这里就是前面提到过的部分。

const blobPart = `${hash}-${index}`;
if (hashData[hash] && hashData[hash][blobPart]) 
{
    // hashData是服务端传回来的数据,判断片段是否存在,存在就跳过
    // 具体可以看看前面
    index++;
    continue;
};

标签:yyds,code,const,web,index,断点续传,res,hash,上传
From: https://blog.51cto.com/u_11365839/6215432

相关文章

  • web基本概念
    1.基本概念1.1前言web:开发:web,网页的意思,www.baidu.com静态web:html.css提供给所有人看的数据始终不会发生变化动态web每个人在不同时间不同地点看到的信息各不相同例如:淘宝,大部分网站...技术栈:Serverlt,ASP,php在java中,动态web资源开发的技术统称为j......
  • Introduction to WebGL 3D with HTML5 and Babylon.js
    Explore3Dbasics,andtakealookat3Dwithouthardware(creatingasoftwareengine).[05:45]-Understanding3DBasicsviaasoftengine[09:49]-UnderstandingtheTransformationpipeline[20:26]-Itsallabouttriangles[31:42]-MovingfromCPUto......
  • 04:基础入门-WEB源码拓展
    前言:WEB源码在安全测试中是非常重要的信息来源,可以用来代码审计漏洞也可以用来做信息突破口,其中WEB源码有很多技术需要简明分析。比如:获取某ASP源码后可以采用默认数据库下载为突破,获取某其他脚本源码漏洞可以进行代码审计挖掘或分析其业务逻辑等,总之源码的获取将为后期的安全......
  • web3 产品介绍: safe --多签钱包 多人审批更放心
    Safe是一款由Gnosis团队开发的多签钱包,它提供了一种安全、灵活和易于使用的方式来管理加密资产。在本文中,我们将介绍Safe的主要特点以及如何使用Safe来保护您的数字资产。一、Safe的特点多重签名:Safe使用多重签名机制来保护用户的资产,需要至少两个签名才能完成交易。这使得用......
  • JavaWeb回顾与小结(一)
    初识前端网页有哪些部分组成文字,图片,音频,视频,超链接网页的本质程序员写的HTML,CSS,JavaScript前端代码前端代码如何转换成网页通过浏览器解析和渲染成用户看到的网页web标准也称网页标准,由一系列的标准组成,大部分由W3C(WorldWideWebConsortium,万维网联盟)复制制......
  • #yyds干货盘点# LeetCode程序员面试金典:最长有效括号
    题目:给你一个只包含'(' 和')' 的字符串,找出最长有效(格式正确且连续)括号子串的长度。 示例1:输入:s="(()"输出:2解释:最长有效括号子串是"()"示例2:输入:s=")()())"输出:4解释:最长有效括号子串是"()()"示例3:输入:s=""输出:0代码实现:classSolution{publicint......
  • #yyds干货盘点# LeetCode面试题:删除排序链表中的重复元素
    1.简述:给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回已排序的链表 。 示例1:输入:head=[1,1,2]输出:[1,2]示例2:输入:head=[1,1,2,3,3]输出:[1,2,3]2.代码实现:classSolution{publicListNodedeleteDuplicates(ListNodehead){......
  • Java WebSocket客户端
    https://www.cnblogs.com/SjhCode/p/WebSocketClient.html注意事项:1.@Scheduled(fixedDelay=5000)2.心跳检测3.导入依赖与导包<dependency><groupId>org.java-websocket</groupId><artifactId>Java-WebSocket</artifactId><version>1.......
  • 关于Nginx作为http-web服务器时对404错误页面的配置
    当我们访问一下Ngin部署的网站时,如果访问一个不存在的资源时,默认服务端会返回404错误,如下所示其实这个页面,我们也是可以自己创建一个页面作为404的返回的,可以通过即可以通过error_page code ...[=[response]] uri;进行配置其他说明:关于error_page指定能写的位置段为:ht......
  • ruoyi整合WebSocket
    https://www.cnblogs.com/SjhCode/p/WebSocket.html ruoyi整合WebSocket这里使用WebSocket目的:向前端推送实时消息,配合ActiveMQ接入三方使用的导入maven依赖 <!--WebSocket--><dependency><groupId>org.java-websocket</groupId><......