文件上传知识点整理

文件上传的方式有多种,在此做个总结,以后用到时方便查询。

首先我们先来看一下 form 表单的格式 multipart/form-data,它表示互联网上的混合资源,意思是资源是有多种元素组成的。multipart/form-data 是在 post 方法的基础上演变来的,具体如下:

  • 基于 post 方法,必须和 post 组合实现
  • 与普通的 post 不同的是 request header 和 request body
  • 请求头必须带上 Context-Type: multipart/form-data,同时还要规定一个分隔符,用于分割表单中的多个项

比如

请求头

Content-Type: multipart/form-data; boundary=--------------------56423498738365

这个 boundary 后面定义的值就是分隔符,会在 body 中用到

请求体

--------------------56423498738365

Content-Disposition: form-data; name="id"



--------------------56423498738365
Content-Disposition: form-data; name="file000"; filename="xxx.png"

Content-Type: image/png

--------------------56423498738365

可以看到表单的每一项都是以分隔符开头,接着是描述信息,在最后再来一个分隔符,表示整个表单的结束。

简单介绍了下 multipart/form-data 的含义,其实不管它是什么类型,只要它是个 http请求,它就逃不出状态行、消息头、消息体这三块内容。下面结束几种文件上传的方式

form 表单

form 表单上传文件应该是最原始也是最简单的方式了

<form method="post" action="后端接口地址" enctype="multipart/form-data">
  <input type="file" name="idcard" id="idcard"/>
  <button type="submit">上传</button>
</form>

如果是要多文件一起上传,<input> 元素上加上 multiple 属性就行了。那么传到后端的这个 idcard 就是一个数组,每个元素是一个文件,相应的后端也要做一点改动

ajax 上传

var file = document.getElementById('idcard').file;
var data = new FormData();
data.append('idcard', file);
// 创建xhr
xhr.send(data);

上传进度

//接着上面
xhr.onprocess = uploadProcess;
xhr.upload.onprocess = uploadProcess;
function uploadProcess (e) {
  if (e.lengthComputable) {
    var percent = (e.loaded / e.total * 100).toFixed(2)
  }
}
xhr.send(data)

这里需要注意几点:

  • e.lengthComputable 是一个状态,标识发送的长度有了变化,可以计算
  • e.loaded 表示发送了多少字节
  • e.total 表示文件的总字节数
  • xhr.upload.onprocess 需要写在 send 之前,不然 e.lengthComputable 不会变化

拖拽上传

<div id="drop-box" ondrop="drop">把文件拖到这里</div>
<button id="submit">上传</button>

function drop (e) {
  e.preventDefault(); // 取消浏览器默认拖拽行为
  var file = e.dataTransfer.files; // 获取拖拽中的文件对象
  // 再按上面的xhr去上传
}

这里知道一点就行了,e.dataTransfer.files 可以获取拖拽中的文件对象

大文件-分片上传

文件过大的时候,单个文件上传可能会超时,也会超得出服务端允许的最大文件限制。这个时候我们就可以把大文件分割成一个个小片段,用 md5 给每个片段加上一个标志。服务端在接收到所有片段后,根据这个标志、顺序、类型把所有的片段在合并成一个大文件,然后删掉这些片段,如此这般就完成了大文件的分片上传功能。

var chunkSize = 1 * 1024 * 1024; // 每个分片的大小 1M
var file = document.getElementById('idcard');
var chunks = [];  // 保存分片数据
 
var start = end = 0;
while (true) {
  end += chunkSize;
  var blob = file.slice(start, end);
  start += chunkSize;
  if (!blob.size) { // 截取的数据为空,结束
    break;
  }
  chunks.push(blob);
}

for (let i=0, l=chunks.length; i<l; i++) {
  var data = new FormData();
  data.append('token', md5());  // 片段标志
  data.append('idcard', chunks[i]); // 所有的片段都放在 idcard 这一项里
  data.append('index', i);  // 标识片段的顺序,服务端会根据这个标志来合并所有的片段
  xhr.send(data, function() {
    // 记数,等到所有片段都发送完,发送一个合并请求
  })
}

这里知道一点就好做了,file 文件对象提供了一个 slice 方法,让我们可以像操作数组一样来操作文件对象。该方法用来截取一段文件对象的二进制内容 blob。

大文件-断点续传

基于文件分片上传,维护一个数组,在每个片段上传成功之后,将当前片段的index放入这个数组,然后存入 localStorage。当下次上传时,先读取这个数组,然后将大文件分片,片段下标已经在这个数组中的就可以不用上传了

 

Demo 地址:https://github.com/gumuqi/file-upload-summary

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值