Как загрузить файл с помощью Koa?

Я настраиваю новый сервер и хочу поддерживать расширенную функцию загрузки. Во-первых, мне нужно проверить файл (тип файла, размер файла, максимальное количество) и, наконец, загрузить его в какое-либо место назначения. Я пробовал что-то с 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

router.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()

Как я могу решить проблему загрузки наилучшим образом для долгосрочного обслуживания кода?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
7 650
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

промежуточное ПО koa похоже на вложенный обратный вызов, вы должны ловить «next()», а не после multer

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, которые не были обнаружены самим контроллером.

Ответ принят как подходящий

Самый простой подход к загрузке файлов следующий (предположим, что в форме есть поле для загрузки файлов с именем 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.info(`path: ${path}`)
        console.info(`filename: ${name}`)
        console.info(`type: ${type}`)
        console.info(`fileExtension: ${fileExtension}`)
        await fs.copy(path, `public/avatars/${name}`)
        ctx.redirect('/')
    } catch(err) {
        console.info(`error ${err.message}`)
        await ctx.render('error', {message: err.message})
    }
})

Обратите внимание, что в этом примере используется Асинхронные функции, что позволяет использовать чистый код со стандартным блоком try-catch для обработки исключений.

Ссылка на песочницу: codeandbox.io/s/koa-body-upload-tt3c2 koajs/koa-body используется из-за необходимости составных частей. Это промежуточное программное обеспечение от первого лица, поддерживаемое потоковым многокомпонентным синтаксическим анализатором и совместным телом.

Ray Foss 13.10.2021 19:04

Вы можете использовать один из двух вариантов:

Первый заключается в добавлении функции обратного вызова в конец маршрута.

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
        })
})        

Второй вариант — добавить try/catch перед вызовом промежуточного ПО multer:

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, оно будет обработано try/catch в предыдущем вызове await next().

Другие вопросы по теме