Koa2 (三)

263 阅读2分钟

Koa2 从入门到精通(三)

koa2-cors 解决跨域问题

var Koa = require('koa');
var cors = require('koa2-cors');
 
var app = new Koa();
app.use(cors({
  origin: function(ctx) {
    if (ctx.url === '/test') {
      return false;
    }
    return '*';
  },
  exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'],
  maxAge: 5,
  credentials: true,
  allowMethods: ['GET', 'POST', 'DELETE'],
  allowHeaders: ['Content-Type', 'Authorization', 'Accept'],
}));

@koa-multer处理图片上传

此处对于图片文件的处理并没有进行完全封装,可根据你的实际需求或情况自行封装,此处详细讲解,单图片上传和多图片上传

需要注意的是存储引擎设置的,文件路径必须得存在,不然会报错,此处我新建了public/images文件夹用来存放图片

image.png

image.png

// utils/imageUpload.js
const multer = require('@koa/multer')
const path = require('path')

// 设置磁盘存储引擎,设置上传文件存放路径、及文件命名,其中images文件夹必须存在,否则会报错
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, './public/images')
  },
  filename: function (req, file, cb) {
    let ran = Math.floor(Math.random()*10000) // 此处随机生成一万以内的整数,来尽量避免重复
    let ext = file.originalname.split('.')[1]
    let fileName = `${Date.now()}${ran}.${ext}`
    cb(null, fileName)
  }
})
// 文件上传限制,文件数量,文件大小等限制
const limits = {
  // fileSize: 250 * 1024, // 文件大小 单位: b ,上面还有kb,mb,所以1024相当于1024b == 1.024kb
  // files: 1 // 文件最大数量
}

// 文件类型过滤
function checkFileType(file, cb) {
  // 允许的扩展名格式
  const filetypes = /jpeg|jpg|png|gif/
  const extname = filetypes.test(path.extname(file.originalname).toLowerCase())
  const mimetype = filetypes.test(file.mimetype)
  if (mimetype && extname) {
    return cb(null, true)
  } else {
    // 上传文件的格式错误
    cb({
      message: 'file type error'
    })
  }
}

// 加载配置,当类型检查和大小限制等一系列的限制回调被执行,会被app.on('error')捕获到
const upload = multer({
  storage,
  fileFilter: function(req, file, cb) {
    checkFileType(file, cb)
  },
  limits
})

module.exports = upload

单图片文件上传

  • 在路由中定义 upload.js 文件,用于处理上传api,并在app.js中使用该路由
const users = require('./routes/users')
const uploads = require('./routes/upload')
app.use(users.routes(), users.allowedMethods())
app.use(uploads.routes(), uploads.allowedMethods())

image.png

const router = require('koa-router')()
const upload = require('./../utils/imageUpload')
const { SuccessModel, ErrorModel} = require('./../model/resModel')

router.prefix('/upload')

router.post('/image/single', async function (ctx, next) {
  let err = await upload.single('file')(ctx, next)
    .then(res=>res).catch(err=>err)
  // 错误捕获
  if (err) {
    ctx.body = new ErrorModel(err.message)
  } else {
    if (ctx.file == undefined) {
      ctx.body = new ErrorModel('不能上传空')
    } else {
      ctx.body = new SuccessModel('success')
    }
  }
})

module.exports = router
  • 前端使用情况

传递的文件必须为表单数据 multipart/form-data

const formData = new FormData(); formData.append('file', file)

image.png

image.png

多图片文件上传

  • 使用upload.array()

image.png

const router = require('koa-router')()
const upload = require('./../utils/imageUpload')
const { SuccessModel, ErrorModel} = require('./../model/resModel')

router.prefix('/upload')

router.post('/image/single', async function (ctx, next) {
  let err = await upload.single('file')(ctx, next)
    .then(res=>res).catch(err=>err)

  // 错误捕获
  if (err) {
    ctx.body = new ErrorModel(err.message)
  } else {
    if (ctx.file == undefined) {
      ctx.body = new ErrorModel('不能上传空')
    } else {
      ctx.body = new SuccessModel('success')
    }
  }
})

router.post('/image/multer', async (ctx, next) => {
  // upload.array(name, maxCount) name表示上传时字段名称,maxCount表示最大数量
  let err = await upload.array('file', 6)(ctx, next)
    .then(res=>res).catch(err=>err)

  // 错误捕获
  if (err) {
    ctx.body = new ErrorModel(err.message)
  } else {
    if (ctx.files.length) {
      ctx.body = new SuccessModel('success')
    } else {
      ctx.body = new ErrorModel('不能上传空')
    }
  }
})

module.exports = router

  • 前端使用情况

image.png

<template>
  <div>
    <input type="file" @change="change" ref="val" multiple>
  </div>
</template>

<script>
export default {
  name: 'Test',
  methods: {
    change() {
      var formData = new FormData()
      var len = this.$refs.val.files.length;
      for (var i = 0; i < len; i++) {
        formData.append('file', this.$refs.val.files[i])
      }
      this.$axios.post('http://localhost:3000/upload/image/multer', formData).then(res => {
        console.log(res)
      })
    }
  }
}
</script>

<style scoped>

</style>
  • 选择的多个文件中,存在其他非图片格式的文件

image.png

  • 都选择图片格式的图片,且数量没有超过限制

image.png

  • 都选择图片格式,但数量超过了设置的6张的限制

image.png

多张图片上传二

  • 相当于upload.array()的升级版,可以传递多个字段

image.png

const router = require('koa-router')()
const upload = require('./../utils/imageUpload')
const { SuccessModel, ErrorModel} = require('./../model/resModel')

router.prefix('/upload')

router.post('/image/single', async function (ctx, next) {
  let err = await upload.single('file')(ctx, next)
    .then(res=>res).catch(err=>err)

  // 错误捕获
  if (err) {
    ctx.body = new ErrorModel(err.message)
  } else {
    ctx.body = new SuccessModel('success')
  }
})

router.post('/image/multer', async (ctx, next) => {
  // upload.array(name, maxCount) name表示上传时字段名称,maxCount表示最大数量
  let err = await upload.array('file', 6)(ctx, next)
    .then(res=>res).catch(err=>err)

  // 错误捕获
  if (err) {
    ctx.body = new ErrorModel(err.message)
  } else {
    ctx.body = new SuccessModel('success')
  }
})

router.post('/image/multer-fields', async (ctx, next) => {
  // upload.fields([{name: '', maxCount: number}]) 
  let err = await upload.fields([{
    name: 'file1',
    maxCount: 1,
  }, {
    name: 'file2',
    maxCount: 2
  }
  ])(ctx, next)
    .then(res=>res).catch(err=>err)

  // 错误捕获
  if (err) {
    ctx.body = new ErrorModel(err.message)
  } else {
    // ctx.files是一个对象里面包含了 {file1:[], file2: []}
    console.log(ctx.files)
    ctx.body = new SuccessModel('success')
  }
})

module.exports = router
  • 前端使用情况,此处就不进行测试了,字段可传可不传

image.png

上传进度条

  • 参考博客
  • 参考博客包含多种网络请求的介绍 XMLHttpRequest、jQuery.ajax、axios
  • 对于上传进度无需后端做过多操作,只需要有上传文件的接口就行了,对于上传进度由前端进行监听
  • 使用,此处上传图片文件比较小,上传速度有点快看不出效果,我手动吧网络调慢了

image.png

<template>
  <div>
    <input type="file" ref="val" multiple>
    <div>
      <progress id="progress" :value="progress" max="100"></progress>
      <span>{{progress}}%</span>
    </div>
    <button @click="upload">上传</button>
  </div>
</template>

<script>
export default {
  name: 'Test',
  data() {
    return {
      progress: 0
    }
  },
  methods: {
    upload() {
      let config = {
        headers: {
          'Content-Type': 'multipart/form-data'
        },
        onUploadProgress: e => {
          const { loaded, total } = e
          if (e.lengthComputable) {
            let progress = loaded / total * 100
            // 向下取整,去掉小数
            progress = Math.floor(progress)
            console.log(progress)
            this.progress = progress
          }
        }
      }
      var formData = new FormData()
      formData.append('file', this.$refs.val.files[0])
      console.log(formData.get('file'))
      this.$axios.post('http://localhost:3000/upload/image/single', formData, config).then(res => {
        console.log(res)
      })
    }
  }
}
</script>

<style scoped>

</style>

image.png image.png