当前位置: 首页 > Web前端 > HTML5

让我们谈谈文件上传和下载

时间:2023-04-05 19:21:59 HTML5

前端开发总是绕不开文件上传下载的需求。让我们总结一下常用的方法。欢迎讨论和投诉。最传统的文件上传方式是使用form表单上传文件。您只需要将enctype设置为multipart/form-data。这种方式不需要js上传文件,不存在兼容性问题。所有浏览器都支持,但是体验很差,导致页面刷新,页面其他数据丢失。选择文件:
标题:
提交注意:输入必须设置name属性,否则无法发送数据。这种文件接口上传的方法由服务端提供接口,设置相应的请求头,前端以formData的形式提交文件数据。accept:表示可选择的文件MIME类型,多个MIME类型用英文逗号分隔multiple:是否可以选择多个文件$('#uploadFile').on('change',function(e){varfile=this.files[0]varformData=newFormData()formData.append('file',file)$.ajax({url:'xxxx',type:'post',data:formData,cache:false,contentType:false,processData:false,success:function(res){//},})})processData设置为false。因为数据值是一个FormData对象,所以不需要进行任何数据处理。cache设置为false,上传文件不需要缓存。contentType设置为false。部分上传有时候我们上传的文件可能非常大,比如视频,可能会达到2G,这会导致上传速度过慢,有时候甚至会出现链接超时的情况。而且有时服务器会设置允许上传的文件大小,过大的文件将不允许上传。为了解决这个问题,我们可以分片上传文件,每次只上传一小部分,比如1M。思路是将文件按照一定的大小(比如1M)切分成一小部分,在分片上加上一个hash值进行标识。将每个切片文件并发提交给服务器,服务器保存每个切片文件的信息。切片上传后,服务器根据文件ID进行合并,合并后删除切片文件。这样,由于每个切片都是并发上传的,因此可以有效减少上传时间。下面说一下具体的实现步骤。(PS:这是我们公司的实现方式,不是唯一的方式,具体接口相关的代码这里就不贴了)生成的哈希。最简单粗暴的hash值可以通过文件名+下标来识别,但是文件名一旦被修改,就失去了作用。其实只要文件内容不变,hash应该也不会变,所以正确的做法是使用文件内容生成hash。我们公司用的是spark-md5库,这里就不赘述了。文件信息上传需要在文件分片上传前上传文件的总文件大小、文件名、哈希值等整个文件信息。主要目的是初始化一个文件片段上传事件,并为每个分片返回Commits的文件ID。getFileId(file){letvm=thisletformData=newFormData()formData.append('file',file)axios({timeout:5*60*1000,headers:{'Content-Type':'application/json-','x-data':JSON.stringify({fileName:file.fileName,size:file.size,hash:'hashxxx',}),},url:'xxxxxx',方法:'POST',}).then((res)=>{if(res.code==='200'){returnres.data.fileId}).catch((err)=>{console.log(err)})}文件切片分割当前端获取到本地图片后,使用Blob.prototype.slice方法(类似数组的切片方法)将大文件按照1M每片切片,返回原文件的一片切片,然后同时将每个分片上传到服务器。getCkunk(file,fileId){letvm=thisletchunkSize=1024*1024lettotalSize=file.sizeletcount=Math.ceil(totalSize/chunkSize)letchunkArr=[]for(leti=0;i{returnres.data.path}).catch((err)=>{console.log(err)})}显示上传进度条。由于文件比较大,即使分块上传也需要一定的时间为了更好的用户体验,前端最好提示上传进度。此时后端需要在每个分片的返回结果中加入上传的100%字段。当前端获取到返回值后,改变当前的进度。当最后一部分上传完成后,服务器返回文件的url,前端获取到url,将进度条的状态改为100%。上面说的分片上传解决了上传大文件超时和服务器的限制。但对于较大的文件,短时间内无法完成上传,有时甚至会面临断线或手动挂起的情况。是否需要重新上传整个文件?当然,我们不想要它。这是恢复传输派上用场的地方。下面说一下实现思路。首先,续传必须建立在分片上传的基础上。上传每个分片时,服务器记录上传文件的哈希值。上传成功后,将哈希值返回给前端。前端记录hash值重新上传时,将每个文件的hash值与记录的hash值进行比较,相同则跳过,继续上传下一段。所有分片上传完毕后,服务器根据文件标识进行合并,合并后删除小文件。文件下载文件下载有几种方法:form表单提交这是最原始的方法,给一个下载按钮添加点击事件,点击时动态生成一个表单,利用表单提交的功能实现文件下载(其实,表单提交就是发送一个请求)。functiondownloadFile(downloadUrl,fileName){//创建一个表单letform=document.createElement('form')form.method='get'form.action=downloadUrl//form.target='_blank';//form是新打开的Pagedocument.body.appendChild(form)form.submit()document.body.removeChild(form)}优点:兼容性好,没有URL长度限制问题。缺点:无法知道下载进度,无法直接下载浏览器可以直接预览的文件类型(如txt/png等)window.open或window.location.href最简单直接的方式,其实用a标签访问下载链接同window.open('downloadFile.zip')location.href='downloadFile.zip'缺点会出现url长度限制问题需要注意url编码问题浏览器即可直接浏览不能下载的文件类型,如txt、png、jpg、gif等,不能添加header,不能进行鉴权,不能知道下载进度。a标签下载属性download属性是HTML5中的一个新属性。为了兼容性,你可以了解我可以使用下载。点击下载点击下载优点:可以解决但不直接下载浏览器可浏览的文件。缺点是无法下载已知的下载文件地址。跨域浏览器可以浏览该文件。存在兼容性问题,尤其是IE无法进行认证。使用Blob对象,该方法不仅可以使用已知的文件地址路径进行下载,还可以通过向api发送ajax请求获取文件流进行下载。可以使用Blob对象将文件流转换为Blob二进制对象。下载的思路很简单:发送获取二进制数据的请求,转化为Blob对象,使用URL.createObjectUrl生成url地址,赋值给a标签的href属性,下载到结合下载。downdFile(path,name){constxhr=newXMLHttpRequest();xhr.open('get',路径);xhr.responseType='blob';xhr.发送();xhr.onload=function(){if(this.status===200||this.status===304){//constblob=newBlob([this.response],{type:xhr.getResponseHeader('内容类型')});//consturl=URL.createObjectURL(blob);consturl=URL.createObjectURL(this.response);consta=document.createElement('a');a.style.display='无';a.href=网址;a.下载=名称;文档.body.appendChild(a);a.点击();文档.body.removeChild(a);URL.revokeObjectURL(url);推荐文章你可能不知道的javascript高级功能总结javascript处理异步的方法总结移动端H5开发常用技巧(干货满满!)从零开始搭建webpack项目总结几种webpack打包优化方法总结前端性能优化方法vue知识体系实用技巧几种常见的JS递归算法,封装一个toast和dialog组件,发布给我关注npm的公众号不定期分享前端知识,与你共同进步!