【问题标题】:How to upload file using Koa?如何使用 Koa 上传文件?
【发布时间】:2019-09-16 05:36:04
【问题描述】:

我正在设置一个新服务器并希望支持高级上传功能。首先,我需要验证文件(文件类型、文件大小、最大计数),最后将其上传到某个目的地。我用 koa-multer 尝试了一些东西,但我无法得到 multer 验证错误。

multer.js

const multer = require('koa-multer')

const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, './public/uploads/')
  },
  filename: function (req, file, cb) {
    var fileFormat = (file.originalname).split('.')
    cb(null, file.fieldname + '_' + Date.now() + '.' + fileFormat[fileFormat.length - 1])
  }
})

const fileFilter = (req, file, cb) => {
  if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
    cb(null, true)
  } else {
    cb(new Error('This is not image file type'), false)
  }
}

const upload = multer({
  storage: storage,
  limits: {
    fileSize: 1024 * 1024 * 1,
    files: 5
  },
  fileFilter: fileFilter
})

module.exports = upload

路由器.js

const Router = require('koa-router')

const multer = require('../middlewares/multer')
const auth = require('../middlewares/auth')
const controller = require('../controllers').userController

const schemas = require('../schemas/joi_schemas')
const validation = require('../middlewares/validation')

const router = new Router()

const BASE_URL = `/users`

router.post(BASE_URL, auth , validation(schemas.uPOST, 'body'), controller.

addUser)
    router.put(`${BASE_URL}/:id`, auth , multer.single('logo')(ctx, (err) => {
  if (err) {
    ctx.body = {
      success: false,
      message: 'This is not image file'
    }
  }
}),  controller.editUser)
router.delete(`${BASE_URL}/:id`, auth , controller.deleteUser)

module.exports = router.routes()

如何以最好的方式解决上传问题,以便长期维护代码?

【问题讨论】:

    标签: node.js koa koa2


    【解决方案1】:

    上传文件最简单的方法如下(假设表单有一个名为avatar的文件上传字段:

    const Koa = require('koa')
    const mime = require('mime-types')
    const Router = require('koa-router')
    const koaBody = require('koa-body')({multipart: true, uploadDir: '.'})
    
    const router = new Router()
    
    router.post('/register', koaBody, async ctx => {
        try {
            const {path, name, type} = ctx.request.files.avatar
            const fileExtension = mime.extension(type)
            console.log(`path: ${path}`)
            console.log(`filename: ${name}`)
            console.log(`type: ${type}`)
            console.log(`fileExtension: ${fileExtension}`)
            await fs.copy(path, `public/avatars/${name}`)
            ctx.redirect('/')
        } catch(err) {
            console.log(`error ${err.message}`)
            await ctx.render('error', {message: err.message})
        }
    })
    

    请注意,此示例使用 Async Functions,它允许使用标准 try-catch 块处理异常的干净代码。

    【讨论】:

    【解决方案2】:

    koa 中间件就像一个嵌套的回调,你应该在 multer 之后不捕获“next()”

    router.put(`${BASE_URL}/:id`, auth , async (ctx, next) => {
      try{
        await next()
      } catch(err) {
        ctx.body = {
          success: false,
          message: 'This is not image file'
        }
      }
    }, multer.single('logo'),  controller.editUser)
    

    但是你这样做,它也会捕获控制器本身没有捕获的 controller.editUser 错误。

    【讨论】:

      【解决方案3】:

      您可以使用以下两个选项之一:

      第一种是在路由末尾添加回调函数。

      const multer = require('@koa/multer')
      
      //Options to limit file size and file extension
      const upload = multer({
              dest: '../avatars',
              limits: {
                  fileSize: 1024*1024
              },
              fileFilter(ctx, file, cb) {
                  if (!file.originalname.match(/\.(jpg|jpeg|png)$/)) {
                      return cb(new Error('Please upload a World document'))
                  }
                  cb(undefined, true)
              }
          })
      
      
      
      //The last callback should handle the error from multer
      router
              .post('/upload', upload.single('upload'), async (ctx) => {
                  ctx.status = 200
              }, (error, ctx) => {
                  ctx.status = 400
                  ctx.body = error.message
              })
      })        
      

      第二种选择是在调用multer中间件之前添加try/catch:

      router
          .post('/upload', async (ctx, next) => {
                    try {
                  await next()
                  ctx.status = 200
              } catch (error) {
                  ctx.status = 400
                  ctx.body = error.message
              }
          }, upload.single('upload'), async ctx => {ctx.status = 200})
      

      最后一种情况,如果multer会抛出异常,会在之前的await next()中由try/catch处理

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-02-28
        • 1970-01-01
        • 1970-01-01
        • 2019-09-10
        • 1970-01-01
        • 1970-01-01
        • 2013-10-24
        • 2020-09-12
        相关资源
        最近更新 更多