1。再简单的需求,当量级达到一定程度时,就会变得极其复杂。文件上传简单,文件变复杂。上传大文件时,以下变量会影响我们的用户体验服务器处理数据请求的能力超时、网络波动、上传时间会变长、高频文件上传失败、失败后需要重新上传等。为了解决以上问题,我们需要单独处理大文件上传。这里涉及到分片上传和断点续传两个概念分区上传就是把要上传的文件按照一定的大小分成多个数据块(Part)进行分片上传,如下图。服务器将所有上传的文件汇总整合为原始文件。大致过程如下:将待上传的文件按照一定的切分规则划分为大小相同的数据块;初始化一个分片上传任务,并返回本次分片上传的唯一标识;按照一定的策略(串行或并行)发送每个分片数据块;发送完成后,服务器判断数据上传是否完成。如果完整则合成数据块得到原文件断点续传续传是指在下载或上传时,人为将下载或上传任务分成若干部分。每个部分使用一个线程来上传或下载。如果出现网络故障,您可以从已经上传或下载的部分继续。上传下载未完成的部分,无需从头开始上传下载。用户可以节省时间并提高速度。一般有两种实现方式:服务器返回告诉浏览器从哪里开始处理上传过程。该文件作为临时文件写入服务器上。这个临时文件可以重命名为正式文件。如果上传中途中断,下次上传会以当前临时文件大小作为客户端读取文件的偏移量。从这个位置开始,继续读取文件数据块,上传到服务器就可以从这个偏移量开始继续写文件了。2.实现思路整体思路比较简单。获取文件,保存文件唯一标识,剪切文件,分段上传,每次上传一段,根据唯一标识判断文件上传进度,直到文件的所有片段都上传完毕,下面的内容是读取文件内容的伪代码:constinput=document.querySelector('input');input.addEventListener('change',function(){varfile=this.files[0];});可以使用md5来实现文件的唯一性constmd5code=md5(file);然后开始分割文件varreader=newFileReader();reader.readAsArrayBuffer(file);reader.addEventListener("load",function(e){//每隔10M分割一段,这里只是分割演示,实际切割需要循环切割,varslice=e.target.result.slice(0,10*1024*1024);});h5uploadone(onepiece)constformdata=newFormData();formdata.append('0',slice);//这里有个坑,有些设备获取不到文件名和文件类型,这个在解决方案formdata.append('filename',file.filename);varxhr=newXMLHttpRequest();xhr.addEventListener('load',function(){//xhr.responseText});xhr.open('POST','');xhr.send(表单数据);xhr.addEventListener('进度',更新进度);xhr.upload.addEventListener('progress',updateProgress);functionupdateProgress(event){if(event.lengthComputable){//进度条}}这里是常见的图片和视频文件类型判断functioncheckFileType(type,file,back){/***typepngjpgmp4...*fileinput.change=>this.files[0]*backcallback(boolean)*/varargs=arguments;如果(args.length!=3){返回(0);}变量类型=args[0];//type='(png|jpg)','png'varfile=args[1];varback=typeofargs[2]=='函数'?args[2]:函数(){};if(file.type==''){//如果系统获取不到文件类型,读取二进制流并解析二进制文件类型varimgType=['ffd8ff',//jpg'89504e',//png'000146674797069736F6D',//mp4'000186674797033677035',//mp4'00006674797033677035',//mp4'0000667479704D534E56',//mp4'00006674797069736F6D',//mp4'00018667479706D703432',//m4v'0000667479706D703432',//m4v'000146674797071742020',//mov'00006674797071742020',//mov'00006D6F6F76',//mov'4F676753002',//ogg'1A45DFA3',//ogg'52494646xxxx41564920',//avi(RIFFfileSizefileTypeLIST)(52494646,DC6C5709,41564920,4C495354)];vartypeName=['jpg','png','mp4','mp4','mp4','mp4','mp4','m4v','m4v','mov','mov','mov','ogg','ogg','avi',];varsliceSize=/png|jpg|jpeg/.test(类型)?3:12;varreader=newFileReader();reader.readAsArrayBuffer(文件);reader.addEventListener("加载",函数(e){varslice=e.target.result.slice(0,sliceSize);读者=空;if(slice&&slice.byteLength==sliceSize){varview=newUint8Array(slice);变量arr=[];view.forEach(function(v){arr.push(v.toString(16));});查看=空;varidx=arr.join('').indexOf(imgType);如果(idx>-1){返回(类型名称[idx]);}else{arr=arr.map(function(v){if(i>3&&i<8){return'x';}returnv;});varidx=arr.join('').indexOf(imgType);如果(idx>-1){返回(类型名称[idx]);}else{返回(假);}}}else{返回(假);}});}else{vartype=file.name.match(/\.(\w+)$/)[1];返回(类型);}}调用方法如下checkFileType('(mov|mp4|avi)',file,function(fileType){//fileType=mp4,//如果枚举中没有列出文件类型,则返回false});上面上传文件的步骤可以改成:formdata.append('filename',md5code+'.'+fileType);剪切上传后会有文件的唯一标识信息,断点续传就变成了后台的一个小逻辑判断终端的主要内容是:根据前端传给后台的md5值,去服务器磁盘查找是否有未完成的文件合并信息(即未完成的半成品文件分片),然后根据上传的分片数返回数据告诉前端从哪个开始上传部分。如果想暂停切片的上传,可以使用XMLHttpRequest的abort方法。3、大文件加速上传使用场景:当文件大小超过预期大小时,可以使用sliceuploadingPart实现多片并行上传,加快上传速度网络环境差:推荐使用分块上传当上传失败时,只需要重传失败的部分流式上传:当上传的文件大小不确定时,可以开始上传。这种场景在视频监控等行业应用中比较常见。当前的伪代码只是一个简单的想法。如果要把事情做到极致,就需要考虑更多的场景,比如切片上传失败怎么办。并行刷新页面怎么办如何并行上传切片什么时候按数量切,什么时候按尺寸切如何结合WebWork处理大文件上传如何实现即时传输生活不是这样的,极致的生活体验有无限可能,越往后才发现越精彩~\_~原文地址https://www.webxiu.com.cn/post/10000462参考资料https://segmentfault.com/a/11...https://baike.baidu.com/
