首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

文件切片上传如何防止切片丢失

上篇文章咱们介绍了大文件切片上传的原理,但是在传输过程中难免出现切片丢失的情况,传输过程中网速卡顿,服务器链接超时,等等都会造成切片信息的丢失,那如何避免文件切片信息丢失呢?

基本思路是,首先我们要计算出文件的MD5值,将MD5值和文件一起传递到服务器,服务器接收到文件读取文件的MD5值,然后跟前端传递的MD5进行比对,相同则文件数据未丢失,不相同证明文件信息丢失。

那什么是MD5呢?英文全称为Message Digest Algorithm MD5(中文名为消息摘要算法第五版),它是计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护,以确保信息传输完整一致。

前端读取文件的MD5值需要用到一个库https://github.com/satazor/js-spark-md5,这个库读取文件MD5值时,需要读取文件的buffer数据,而读取文件的buffer数据需要用到html5的文件读取接口fileReader api。所以前端读取文件MD5值的核心技术是js-spark-md5和fileReader api。

将文件切片上传,并且将文件的MD5读取出来后一起发送到后端,代码如下。

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>文件切片上传</title>
    <script src="http://code.jquery.com/jquery-3.2.1.min.js"></script>
    <script src="./uuid.js"></script>
    <script src="./js-spark-md5.js"></script>
</head>

<body>
    <form action="/upload2" method="post" enctype="multipart/form-data">
        <input name="test" type="file" id="img">
    </form>
</body>
<script>
    function p(formdata) {
        return new Promise(function (resolve, reject) {
            $.ajax({
                url: "/upload2",
                type: "POST",
                data: formdata, //刚刚构建的form数据对象
                async: true, //异步
                processData: false, //很重要,告诉jquery不要对form进行处理
                contentType: false, //很重要,指定为false才能形成正确的Content-Type
                success: function (data) {
                    resolve(data);
                }
            })
        })
    }
    
    $(function () {
        // 1.实例化文件读取方法对象
        var reader = new FileReader();
        // 2.实例化读取buffer MD5方法
        var spark = new SparkMD5.ArrayBuffer();
        var input = document.querySelector('input');
        // 3.监听上传文件input的change事件
        input.addEventListener('change', function () {
            //4. 获取文件blob信息
            var file = this.files[0];
            console.log(file);
            // 5.将blob读取为buffer信息,这一步是异步操作
            reader.readAsArrayBuffer(file);
            // reader.readAsBinaryString(file);
        });
        //  6.监听读取blob信息完成事件
        reader.addEventListener("load", function (e) {
            var chunksize = 1 * 1024 * 1024;
            // 7、将buffer信息转化为blob,为了传输
            var blob = new Blob([e.target.result]);
            console.log(blob.toString())
            ///8、用spark直接读取文件的MD5值,
            spark.append(e.target.result);
            ///9、读取完成,用一个变量来接收
            let SparkMD5 = spark.end();
            console.log(SparkMD5)
            var count = Math.ceil(blob.size / chunksize);
            var uuidfolder = uuidv1();
            var arr = []
            async function main() {
                for (let i = 0; i < count; i++) {
                    var slice = blob.slice(i * chunksize, (i + 1) * chunksize);
                    var formdata = new FormData();
                    formdata.append('imgname', uuidfolder);
                    formdata.append('imgorder', i);
                    formdata.append('img', slice);
                    var a = await p(formdata);
                    arr.push(a);
                }
            }
            main().then(function () {
                //10、 将md5值发送到服务器端。
                $.post('/merge2',{id:uuidfolder,spark:SparkMD5},function(data){
                            console.log(data);
                })
            })
        });
    })
</script>

</html>

代码详解见注释,主要的是注意FileReader和 SparkMD5的运用。

服务器接收到前端发送的数据后,将切片拼接为一个完整文件,然后读取该文件的MD5值,和前端传过来的MD5值进行比对,如果相等证明切片未丢失,如果不相等,证明切片丢失。代码如下:

代码语言:javascript
复制
router.post('/merge2',function(req,res){
  let id = req.body.id;
  let spark = req.body.spark;
  let folderpath = path.join(__dirname,"..",'public/uploads',id);
  let destinpath = path.join(__dirname,"..",'public/img',id+'.jpg');
  let dist = '/img/'+id+'.jpg'
  fs.readdir(folderpath,function(err,arr){
    let arr2 = arr.map(e=>path.join(folderpath,e));
    concat(arr2, destinpath, function(err) {
      // fs.readFile(destinpath,function(err,data){
      //     if (err) throw err
      //     res.send(dist);
      // })
      // 1、此处使用了两个库来读取文件的MD5值
      // 分别是md5和spark-md5(和前端用的同样的库)
       
      var md5sum = crypto.createHash('md5');
      var frontspark = new SparkMD5.ArrayBuffer();
      // 2、由于读取文件的MD5值非常耗时,
      // 所以这里应用了文件的流模式读取文件的MD5值
      var stream = fs.createReadStream(destinpath);
      stream.on('data', function(chunk) {
          md5sum.update(chunk);
          frontspark.append(chunk)
      });
      stream.on('end', function() {
          str = md5sum.digest('hex');
          str2 = frontspark.end()
          if (err) throw err
          console.log(str,spark,str2);
          if(str = spark){
            res.send(dist);
          }    
      });    
    });
  })
})

项目源码地址:https://github.com/clm1100

下一篇
举报
领券