Egg文件上传接收总结
egg获取上传文件的方法官方提供了两种处理方式,一种是直接读取文件,一种是流式处理。文件读取方式先来看文件读取方式,需要先在config中配置//config.defult.jsconfig.multipart={mode:'file'};控制层代码constfs=require('fs')constpath=require('path')constController=require('egg').Controller;classHomeControllerextendsController{asyncindex(){const{ctx}=this;//console.log(ctx.request.body)letfile=ctx.request.files[0]//file包含文件名,文件类型,大小,路径等信息,可以自己打印看看//读取fileletfile=fs.readFileSync(file.filepath)//files[0]表示获取第一个文件,如果前端上传多个文件,可以遍历这个数组对象//将文件保存到指定位置fs.writeFileSync(path.join('./',`uploadfile/test.png`),file)//ctx.cleanupRequestFiles()ctx.body={code:200,message:'',data:file.filename}}}前端上传文件代码(这里使用Vue+axios)
运行上面的代码后,在egg项目的uploadfile目录下可以找到流式传输上传文件的方法。单个文件可以使用getFileStream方法获取文件流。注意,使用stream流方式时需要删除之前配置中的multipart。这两个方法不能一起使用,否则会报错。constfs=require('fs')constpath=require('path')constquerystring=require('querystring');constsendToWormhole=require('stream-wormhole');constController=require('egg').控制器;类HomeController扩展控制器{asyncindex(){const{ctx}=this;letstream=awaitctx.getFileStream()letfilename=newDate().getTime()+stream.filename//流对象还包含文件名、大小等基本信息//创建文件写入路径lettarget=path.join('./',`uploadfile/${filename}`)constresult=awaitnewPromise((resolve,reject)=>{//创建文件写入流constremoteFileStrem=fs.createWriteStream(target)//通过管道写入流stream.pipe(remoteFileStrem)leterrFlag//监听错误事件remoteFileStrem.on('error',err=>{errFlag=true//停止写入sendToWormhole(stream)remoteFileStrem.destroy()console.log(err)reject(err)})//监听写入完成事件remoteFileStrem.on('finish',()=>{if(errFlag)returnresolve({filename,name:stream.fields.name})})})ctx.body={code:200,message:'',data:result}}}前端上传多个文件codeupload(){letfiles=this.$refs.fileid.filesletformData=newFormData()//遍历文件for(leti=0;i
{console.log(res)})}getFileStream是上传文件时使用的方法。如果上传多个文件,该方法只能获取其中一个文件。对于多个文件上传,应该使用multipart方法。constfs=require('fs')constpath=require('path')constquerystring=require('querystring');constController=require('egg').Controller;classHomeControllerextendsController{asyncindex(){const{ctx}=这个;常量部分=ctx.multipart();让部分;while((part=awaitparts())!=null){if(part.length){//处理其他参数console.log('field:'+part[0]);console.log('值:'+part[1]);console.log('valueTruncated:'+part[2]);console.log('fieldnameTruncated:'+part[3]);}else{if(!part.filename){继续;}//否则,它是一个流console.log('field:'+part.fieldname);console.log('文件名:'+part.filename);console.log('编码:'+part.encoding);console.log('mime:'+part.mime);让writePath=path.join('./',`uploadfile/${newDate().getTime()+part.filename}`)让writeStrem=fs.createWriteStream(writePath)awaitpart.pipe(writeStrem)}}ctx.body={code:200,message:'',data:result}}}两种方式对比,很明显要记下文件读取的方式就简单多了,但是两者在性能上有什么区别呢?egg到底是怎么实现的呢?使用文件读取的方式,我们可以得到filepath的路径,这个是用来缓存文件的,你可以打印出来看看。可以在此路径中找到上传的文件。也就是说,文件读取方式是先在服务器中写入缓存文件,然后我们读取缓存文件进行操作。在上面的文件操作中,文件读取方式的IO操作包括写缓存文件、读缓存文件和写文件,一共3个IO操作。stream方式没有缓存文件的操作,也就是说只有一个IO操作。如果OSS不是写到服务器而是上传,就没有IO操作。所以这两种方法的效果和性能就不用多说了。配置选项文件读取方式由于有文件缓存,可以配置缓存文件的位置和自动清除时间config.multipart={mode:'file',tmpdir:path.join(os.tmpdir(),'egg-multipart-tmp',appInfo.name),//配置文件缓存目录cleanSchedule:{cron:'0304***',//自动清除时间},};也可以直接在代码中使用cleanupRequestFiles()方法来清空,当然如果选择streaming的方式就不用管这些了。配置文件类型和大小config.multipart={whitelist:[//只允许上传png格式'.png',],fileSize:'5mb',//最大5mb};