Как я могу вернуть Multer Error клиенту при использовании Express-Validator?

Обновленная запись: прокрутите страницу вниз для получения обновленной информации.


Оригинальный пост

Мне нужна помощь в этом. Я создаю маршрут, который принимает FormData, проверяет данные файла через Multer (изображения в данном случае), затем проверяет строковые данные с помощью Express-Validator. Я создал рабочий маршрут, который завершает обе проверки, но я не могу понять, как принять какие-либо ошибки от Multer и вернуть их клиенту.

Я установил Multer перед Express-Validator, чтобы req.body мог быть прочитан Express-Validator. При этом я не могу понять, как (или могу ли я вообще) передавать ошибки Малтера для отправки обратно в ответ.

Мой пример ниже должен включать в себя все необходимое для экзамена, но если вам нужна дополнительная информация, пожалуйста, дайте мне знать.

const multer = require('multer')
const {
    check,
    validationResult
} = require('express-validator/check');
const {
    sanitizeBody
} = require('express-validator/filter');


const imageUpload = multer({
    dest: 'uploads/',
    limits: {
        fileSize: 1000000
    },
    fileFilter: function (req, file, cb) {
        let filetypes = /jpeg|jpg/;
        let mimetype = filetypes.test(file.mimetype);
        let extname = filetypes.test(path.extname(file.originalname).toLowerCase());
        if (mimetype && extname) {
            return cb(null, true);
        }
        cb(new Error('Invalid IMAGE Type'))
    }
}).fields([{
        name: 'cover_image',
        maxCount: 1
    },
    {
        name: 'more_images',
        maxCount: 2
    }
])


const validationChecks = [
    check('street', 'Invalid Street Name').matches(/^[a-z0-9 ]+$/i).isLength({
        min: 1,
        max: 25
    }).trim().escape(),
    check('city', 'Invalid City Name').matches(/^[a-z ]+$/i).isLength({
        min: 1,
        max: 15
    }).trim().escape()
]


router.post('/addnewproperty', imageUpload, validationChecks,(req, res, next) => {  
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
        console.log('text validation FAILED');
        return res.status(400).json({
            errors: errors.array()
        });
    }
    console.log('validation PASSED');
})

Обновление 6/6/19

Хорошо, я думаю, что нашел решение, хотя и не то, что ожидал.

Используя next() Я могу использовать Multer в первом обработчике маршрута, где я могу получать и отправлять ошибки Multer в ответе. Если в этом первом обработчике маршрута не возникает ошибок, я могу позвонить next(), чтобы затем перейти к следующему обработчику маршрута для использования экспресс-валидатора, где я могу проверить и отправить любые ошибки, которые возникают в результате проверки строки.

Код ниже является рабочим примером того, что я описываю. Не уверен, что это приемлемый код, но он работает после небольшого тестирования. Любые мнения или рекомендации по этому поводу приветствуются в комментариях ниже.


// Here's the meat of what I changed.  
// The config and variables set in the previous code are the same. 

router.post('/addnewproperty',(req, res, next) => {
    imageUpload(req,res,(err)=>{
        if(err){
            console.log(err.message);
            return res.status(400).json(err.message)
        }
        next()
    })
})

router.post('/addnewproperty',validationChecks,(req,res)=>{
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
        return res.status(400).json({
            errors: errors.array()
        });
    }
    return res.sendStatus(200)
})

Я оставлю этот вопрос открытым, если у кого-то есть лучшее решение для получения того, что я изначально намеревался сделать, кроме кода выше.

4 ответа

Я использовал функцию, которая создает промежуточное ПО Multer, которое можно разместить в любом месте цепочки промежуточного ПО. После этого вы можете использовать req.body без других двоичных полей.

import { Router } from 'express';
import multer from 'multer';

function makeMulterUploadMiddleware(multerUploadFunction) {
    return (req, res, next) =>
        multerUploadFunction(req, res, err => {
            // handle Multer error
            if (err && err.name && err.name === 'MulterError') {
                return res.status(500).send({
                    error: err.name,
                    message: `File upload error: ${err.message}`,
                });
            }
            // handle other errors
            if (err) {
                return res.status(500).send({
                    error: 'FILE UPLOAD ERROR',
                    message: `Something wrong ocurred when trying to upload the file`,
                });
            }

            next();
        });
}

const upload = multer({ dest: 'uploads/' });

const multerUploadMiddleware = makeMulterUploadMiddleware(upload.single('image'));

const someRouter = Router();

someRouter.post('', multerUploadMiddleware, (req, res) => {
    // now body contains all the fields except the one with the file
    res.send(req.body);
});

export { someRouter };

Я обрабатываю req.body с помощью пакета @ hapi / joi npm, но это должно работать с другими валидаторами.

примечание: причина, по которой я не использую err instanceof multer.MulterErrorчтобы проверить, является ли ошибка Multer, как описано в документации Multer (https://github.com/expressjs/multer), из-за некоторых ошибок проверки типов в машинописном тексте.

Вы можете получить ошибку, позвонив imageUpload связующее ПО напрямую, вместо использования его в цепочке промежуточного ПО, как в вашем коде.

Непроверенный фрагмент, но, надеюсь, по крайней мере подтолкнет вас в правильном направлении:

router.post('/addnewproperty', validationChecks, (req, res, next) => {  
    const errors = validationResult(req);

    if (!errors.isEmpty()) {
        console.log('text validation FAILED');
        return res.status(400).json({
            errors: errors.array()
        });
    }

    imageUpload(req, res, (multerErr) => {
        if(multerErr){
            console.log('Multer validation FAILED');
            return res.status(400).json({
                errors: [multerErr.message]
            });
        }else{
            console.log('validation PASSED');
        }  
    });
})

Для получения дополнительной информации по этому вопросу приведены официальные документы Multer по обработке ошибок.

Эй, я оставлю тебя с некоторыми фрагментами, которые работали для меня,

  • Multer без использования файла

    const express = require('express');
    const multer = require('multer');
    const router = express.Router();
    const { check, validationResult } = require('express-validator');
    
    var upload = multer();
    
    var tagCreateValidator = [
      check('name', 'Name is required')
        .not()
        .isEmpty()
    ];
    
    // @route   POST api/tags
    // @desc    Create Tag
    // @access  Public
    router.post('/', upload.any(), tagCreateValidator, (req, res, next) => {
      const errors = validationResult(req);
      if (!errors.isEmpty()) {
        return res.status(400).json({ errors: errors.array() });
      }
    
      res.send(req.body);
    });
    
  • это с файлом, хотя я не использую экспресс валидатор прямо сейчас, я обновлю этот ответ, как только это будет сделано

    const express = require('express');
    const Multer = require('multer');
    const gcsMiddlewares = require('../../gcs_middleware');
    const router = express.Router();
    
    const multer = Multer({
      storage: Multer.storage,
      limits: {
        fileSize: 10 * 1024 * 1024 //Maximum file size is 10MB
      }
    });
    
    // @route   POST api/users
    // @desc    Register user
    // @access  Public
    router.post(
      '/',
      multer.single('avatar'),
      gcsMiddlewares.sendUploadToGCS,
      (req, res, next) => {
        var imageUrl;
        if (req.file && req.file.gcsUrl) {
          imageUrl = req.file.gcsUrl;
        }
        var responseBody = {
          file: imageUrl,
          body: req.body
        };
    
        res.send(req);
      }
    );
    
    module.exports = router;
    

Я столкнулся с этой проблемой сегодня, за исключением того, что я не использую маршрутизатор. Я хотел иметь возможность вернуть ответ JSON об ошибке, когда проверка типа файла не удалась. Я подумал, что поделюсь своим решением, так как оно может помочь кому-то еще. Мое решение состояло в том, чтобы добавить четвертый параметр к вызову функции app.post() следующим образом:

      app.post("/post", fileUpload.single('file'), function(req, res) { 
    //do some stuff after a successful upload.
}, 
function(err, req, res, next) {
    //File upload encountered an error as returned by multer
    res.status(400).json({error: err.message});
})
Другие вопросы по тегам