备注: 目前只是探索下实现的思路并不带任何规则和业务
原料:
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 对象
Blob.slice 的用法类似 Array.slice() 的感觉
前端代码:
- <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 "上传失败!";
- }
- }
来源: http://www.qdfuns.com/article/31238/623478b6b8c481f1efeb2d1a6e264d44.html