javaScript 文件分片上传思路

技术 解决方案 前端

JavaScript

2018-06-23 19:07:15

253

作者:黑夜男神

备注: 目前只是探索下实现的思路并不带任何规则和业务

原料:

1.Blob对象

一个 Blob对象表示一个不可变的, 原始数据的类似文件对象。Blob表示的数据不一定是一个JavaScript原生格式。 File 接口基于Blob,继承 blob功能并将其扩展为支持用户系统上的文件。

2.FormData 对象

通过FormData对象可以组装一组用 XMLHttpRequest发送请求的键/值对。它可以更灵活方便的发送表单数据,因为可以独立于表单使用。如果你把表单的编码类型设置为multipart/form-data ,则通过FormData传输的数据格式和表单通过submit() 方法传输的数据格式相同。

场景:

1.我们在进行大文件上传的时候,因为服务器的限制,会限制每一次上传到服务器的文件大小不会很大,这个时候我们就需要把一个需要上传的文件进行切割,然后分别进行上传到服务器
2. 在网页中直接上传大文件的时候上传时间长,中途一但网络不稳定会导致前功尽弃所以可以采用对文件进行分片上传。

实现思路:
获取要上传文件的File对象,根据chunk(每片大小)对文件进行分片通过post方法轮循上传每片文件信息;post body中存放本次要上传的二进制数据片段slice用于文件分片上传分片与并发结合,将一个大文件分割成多块,并发上传,极大地提高大文件的上传速度。当网络问题导致传输错误时,只需要重传出错分片,而不是整个文件。另外分片传输能够更加实时的跟踪上传进度。
其实File接口就是基于Blob,继承blob功能并将其扩展为支持用户系统上的文件,也就是说File接口中的Flie对象就是继承与Blob对象
此图可以看处File 原型链上有Blob对象
[color=#f20257]Blob.slice的用法类似 Array.slice() 的感觉[/color]

图片描述

前端代码:

<template>
  <div>
      <input id="file" type="file" name="image" ref="file"  >
  </div>
</template>

<script>
import axios from 'axios'
import UploadSlice from '../upload.js'
export default {
  name: '',
  data () {
    return {    
    }

  },
  mounted () {    
    new UploadSlice({
      url: 'api/upload',
      el:  document.getElementById('file'),
      bytesPer: ''
    })
  },
</script>
import axios from 'axios'

class UploadSlice {    
    constructor (option) { 
      this.url = option.url;
      this.bytesPer = 1024 * 1021  || option.bytesPer // 默认每个文件切片大小为1MB .
      this.el = option.el // Dom 对象
      this.init()
    }
    init () {
      this.changePost()
    }
    changePost () {  
      this.el.onchange = (e) => {
        var startSize = 0     // 每一次开始切割位置
        var endSize = this.bytesPer        
        var file = e.target.files[0]
        var totalSize = Math.ceil(file.size / this.bytesPer); // 总文件大小
        var filesize = file.size;      // 文件大小
        var filename = file.name;      // 文件名
        var blob = []
        for (var i = 0 ; i < totalSize; i++ ) {

          endSize = startSize + this.bytesPer
          var chunk = file.slice(startSize,endSize);  //切割文件 
          let dataForm =  new FormData()
          startSize = endSize 
          dataForm.append('file', chunk, filename) 

          axios.post("api/upload",dataForm,{ headers : { 'Content-Type': 'multipart/form-data'} }).then((res) => {
            console.log(res)
          })  
        }    
      }
    }
}
export default UploadSlice

后端代码:

目前后端代码还有些问题文件上传不完整出现这样的情况后续再研究

图片描述

package com.example.upload;

import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
@RestController
@RequestMapping("/api")
public class Upload {
    private   Date date = new Date();
    @PostMapping(value = "/upload")
    public String upload (@RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            return "上传失败,请选择文件";
        }
        // 获取文件名
        String fileName = file.getOriginalFilename();
        // 存放路径
        String filePath = "/Users/wangxiping/back/upload/src/main/resources/upload/";

        File dest = new File(filePath + date.getTime() + fileName);
        System.out.println(file);
        try {
            file.transferTo(dest);
            return"上传成功";

        } catch (IOException e) {
           System.out.println(e);
        }
        return "上传失败!";
    }
}

评论 (0)

用户名
邮箱
评论

    Copyright © 2020 darkNightMan All Rights Reserved Pro 黔ICP备20005477号