const  upload =  require ( 'koa-multer' )  ( { dest:  './public/images' } ) ; 
router. post ( '/upload' ,  upload. single ( 'file' ) ,  ctx=> { console. log ( 'file' ,  ctx. req. file) ; console. log ( 'body' ,  ctx. req. body) ; ctx. body =  '上传成功' ; 
} ) 
 
1.通过浏览器访问url: http://localhost:3000/upload 2.服务器(koa)监听到对应的路由,调用路由处理函数 3.使用nunjucks模板引擎进行渲染,并返回给浏览器 4.浏览器渲染完毕后显示出来. 5.点击上传文件->上传 6.服务端监听到上传的POST请求,进行相应的处理并将处理结果返回给前端 const  koa =  require ( 'koa' ) ; 
const  app =  new  koa ( ) ; 
const  router =  new  require ( 'koa-router' ) ( ) ; 
const  multer =  require ( 'koa-multer' ) ; 
const  nunjucks =  require ( 'koa-nunjucks-2' ) ; 
const  path =  require ( 'path' ) ; 
const  fs =  require ( 'fs' ) ; 
app. use ( nunjucks ( { ext:  'html' , path:  __dirname, nunjucksConfig:  { trimBlocks:  true } 
} ) ) ; 
const  upload =  multer ( { dest:  'uploads/' 
} ) ; const  types =  upload. single ( 'avatar' ) ; 
router. get ( '/upload' ,  async  ( ctx,  next)  =>  { await  ctx. render ( 'upload' ) 
} ) router. post ( '/profile' ,  types,  async   ( ctx,  next)  =>  { const  {  originalname,  path:  out_path,  mimetype}  =  ctx. req. file; let  newName =  out_path +  path. parse ( originalname) . ext; let  err =  fs. renameSync ( out_path,  newName) ; let  result; if ( err) { result =  JSON . stringify ( err) ; }  else  { result =  `<h1>upload success</h1>` ; } ctx. body =  result; 
} ) ; app. use ( router. routes ( ) ) ; app. listen ( 3000 ,  async  ( )  =>  { console. log ( 'Server is running at http://localhost:3000' ) ; 
} ) 
<!DOCTYPE html> 
< htmllang = " en" > < head> < metacharset = " UTF-8" > < title> </ title> </ head> < body> < formmethod = " post" action = " /profile" enctype = " multipart/form-data" > < inputname = " avatar" id = " upfile" type = " file" /> < inputtype = " submit" value = " 提交" /> </ form> </ body> </ html> <!DOCTYPE html> 
< htmllang = " en" > < head> < metacharset = " UTF-8" > < metaname = " viewport" content = " width=device-width, initial-scale=1.0" > < metahttp-equiv = " X-UA-Compatible" content = " ie=edge" > < scriptsrc = " https://cdn.jsdelivr.net/npm/vue/dist/vue.js" > </ script> < scriptsrc = " https://unpkg.com/element-ui/lib/index.js" > </ script> < linkrel = " stylesheet" href = " https://unpkg.com/element-ui/lib/theme-chalk/index.css" > < style> .avatar-uploader .el-upload { border :  1px dashed #d9d9d9; border-radius :  6px; cursor :  pointer; position :  relative; } .avatar-uploader-icon { font-size :  28px; color :  #8c939d; width :  178px; height :  178px; line-height :  178px; text-align :  center; } .avatar { width :  178px; height :  178px; display :  block; } </ style> < title> </ title> </ head> < body> < divid = " app" > < el-uploadclass = " avatar-uploader" action = " http://localhost:3000/users/upload" :show-file-list = " false" :on-success = " handleAvatarSuccess" :before-upload = " beforeAvatarUpload" > < imgv-if = " imageUrl" :src = " imageUrl" class = " avatar" /> < iv-else  class = " el-icon-plus avatar-uploader-icon" > </ i> </ el-upload> </ div> < script> var  app =  new  Vue ( { el: "#app" , data ( ) { return  { imageUrl: "" } ; } , methods:  { handleAvatarSuccess ( res,  file) { this . $message. success ( "上传头像成功" ) ; this . imageUrl =  URL . createObjectURL ( file. raw) ; } , beforeAvatarUpload ( file)  { const  isJPG =  file. type ===  'image/jpeg' ; const  isLt2M =  file. size /  1024  /  1024  <  2 ; if ( ! isJPG) { this . $message. error ( "上传头像图片只能是 JPG 格式!" ) ; } if ( ! isLt2M) { this . $message. error ( "上传头像图片大小不能超过 2MB!" ) ; } return  isJPG &&  isLt2M; } } , } ) </ script> </ body> </ html>