前言正常的业务需求:上传图片、Excel等,毕竟几M的大小也能快速上传到服务器。上传几百M、几G的视频等大文件,需要等待很长时间。这创建了相应的解决方案。对于大文件上传出现卡顿、断线、网络状况不佳的情况,使用切片+断点续传可以很好的解决上述情况。解决方案分析切片是对上传视频进行切分,具体操作是:File.slice(start,end):返回一个新的blob对象复制blob的起始字节复制blob的结束字节取上传切片的个数同一个文件上传一个新文件,服务器返回0,否则返回上传的切片数。具体解决过程本demo提供了关键思路和方法,其他功能如:文件限制、lastModifiedDate检查文件是否重复、可以在本代码的基础上增加定期清除缓存文件等功能扩展。html部分submitscript部分让我们计数=0;//记录需要上传的文件的下标consthandleVideo=async(event,name,url)=>{//阻止浏览器的默认表单事件event.preventDefault();letcurrentSize=document.querySelector("h2");letfiles=document.querySelector(name).files;//默认的分片个数constsectionLength=100;//先请求接口获取文件在服务器上是否存在//如果计数为0,为第一次上传,计数不为0,则文件存在于服务器,返回上传的分片数count=awaithandleCancel(files[0]);//声明数组对象用于存储切片letfileCurrent=[];//循环文件对象for(constfileof[...files]){//获取每个切片的大小letitemSize=Math.ceil(file.size/sectionLength);//循环文件大小,文件blob存储在数组中letcurrent=0;for(current;current90){source.cancel("取消请求");}//保存Enter文件相关信息//file为切片blob对象//filename为文件名//index为当前切片数//total为切片总数letformData=newFormData();formData.append("文件",item.file);formData.append("文件名",文件名);formData.append("总计",sectionLength);formData.append("index",index+count+1);awaitaxios({url:`http://localhost:8080/${url}`,method:"POST",data:formData,cancelToken:source.token,}).then((response)=>{//返回数据显示进度currentSize.innerHTML=`progress${response.data.size}%`;}).catch((err)=>{console.log(err);});}}};//请求接口,查询上传的文件是否存在//如果计数为0,则表示不存在,如果计数不为0,则对应的切片数已经上传consthandleCancel=(file)=>{returnaxios({method:"post",url:"http://localhost:8080/getSize",headers:{"Content-Type":"application/json;charset=utf-8"},数据:{文件名:文件名,},}).然后((res)=>{returnres.data.count;}).catch((err)=>{console.log(err);});};相关nodejs进阶视频讲解:进入学习nodeserver部分//使用express搭建服务器apiconstexpress=require("express");//引入上传文件逻辑代码constupload=require("./upload_file");//处理所有响应,设置跨域app.all("*",(req,res,next)=>{res.header("Access-Control-Allow-Origin","*");res.header("Access-Control-Allow-Headers","X-Requested-With");res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");res.header(“访问控制允许标题”,“内容类型,X-Requested-With");res.header("X-Powered-By","3.2.1");res.header("Content-Type","application/json;charset=utf-8");next();});constapp=express();app.use(bodyParser.json({type:"application/*+json"}));//视频上传(查询当前切片数)app.post("/getSize",upload.getSize);//视频上传接口app.post("/video",upload.video);//开启本地端口监听app.listen(8080);upload_file//文件上传模块constformidable=require("formidable");//文件系统模块constfs=require("fs");//系统路径模块constpath=require("path");//操作写入文件流consthandleStream=(item,writeStream)=>{//读取对应的目录文件缓冲区constreadFile=fs.readFileSync(item);//将读取缓冲区||chunk写入流writeStream.write(readFile);//写入完成后,清除临时分片filefs.unlink(item,()=>{});};//视频上传(切片)module.exports.video=(req,res)=>{//创建解析对象constform=newformidable.IncomingForm();//设置视频文件上传路径letdirPath=path.join(__dirname,"video");form.uploadDir=dirPath;//是否保留上传文件名的后缀form.keepExtensions=true;//err错误对象如果解析失败包含错误信息//fields包含formData的key-value除了二进制对象//文件对象类型上传文件信息form.parse(req,async(err,fields,file)=>{//获取上传的文件blob对象letfiles=file.file;//获取当前切片索引letindex=fields.index;//获取切片总数lettotal=fields.total;//获取文件名letfilename=fields.filename;//重写上传的文件名并设置临时目录leturl=dirPath+"/"+filename.split(".")[0]+`_${index}.`+filename.split(".")[1];try{//同步修改上传的文件名fs.renameSync(files.path,url);console.log(url);//异步处理setTimeout(()=>{//判断最后一个切片是否上传,拼接写入所有视频if(index===total){//同步创建新目录来存储完整的视频letnewDir=__dirname+`/uploadFiles/${Date.now()}`;//创建目录fs.mkdirSync(newDir);//创建一个用于写入文件的可写流letwriteStreamm=fs.createWriteStream(newDir+`/${文件名}`);让fsList=[];//取出所有分片文件放入数组中for(leti=0;i{letcount=0;req.setEncoding("utf8");req.on("data",function(data){letname=JSON.parse(data);letdirPath=path.join(__dirname,"video&qu哦;);//计算上传切片文件的个数letfiles=fs.readdirSync(dirPath);files.forEach((item,index)=>{leturl=name.fileName.split(".")[0]+`_${index+1}.`+name.fileName.split(".")[1];如果(files.includes(url)){++count;}});res.send({code:0,msg:"请继续上传",count,});});};逻辑分析前端先请求上传,检查文件是否是第一次上传,或者是否有对应的切片文件是第一次上传,则切片从0开始,如果文件中已经有对应的切片,请求上传一个从切片数开始的循环切片数组,上传每个切片文件。使用模拟的手动暂停请求。当分片数大于90时,取消请求服务器接收查询文件filename,查找暂存文件地址,判断是否有对应的未上传过的上传文件,返回0,并且从0开始上传的分片个数,则返回对应的分片个数接收上传的文件分片,将文件存放在暂存目录,通过count和total判断分片是否上传。上传后创建文件存储目录,并创建可写流,执行写操作,提取对应的临时文件放入数组,循环文件目录数组,依次读写文件缓冲区。Write输入完成后,关闭可写流。总结上述代码涉及具体业务流程的变更或偏差。这只是其中一种具体的实现方式。希望这篇文章能对大家有所帮助。如果有不对的地方,还望指点。