2
votes

Comment puis-je renvoyer une erreur Multer au client tout en utilisant Express-Validator?

Message mis à jour: Faites défiler vers le bas pour obtenir des informations mises à jour

Message d'origine

J'ai besoin d'aide pour celui-ci. Je crée un itinéraire qui prend FormData, valide les données du fichier via Multer (images dans ce cas), puis valide les données de chaîne en utilisant Express-Validator . J'ai créé un itinéraire de travail qui termine les deux validations, mais je ne parviens pas à comprendre comment récupérer les erreurs de Multer et les renvoyer au client.

J'ai défini Multer avant Express-Validator , afin que le req.body puisse être lu par Express-Validator . Avec cela, je ne peux pas comprendre comment (ou si je suis capable du tout) de transmettre les erreurs Multer pour renvoyer la réponse.

Mon exemple ci-dessous devrait inclure tout ce qui est nécessaire pour l'examen, mais si vous avez besoin d'informations supplémentaires, veuillez me le faire savoir.

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

Mise à jour 2/6/19

D'accord, je pense avoir trouvé une solution , mais pas ce à quoi je m'attendais.

En utilisant la fonction next () dans express, je suis capable d'utiliser Multer dans le premier gestionnaire d'itinéraire où je peux recevoir et renvoyer les erreurs Multer dans la réponse. Si aucune erreur ne se produit dans ce premier gestionnaire de route, je peux appeler next () , pour ensuite passer au gestionnaire de route suivant pour utiliser express-validator où je peux vérifier et envoyer toutes les erreurs qui résultent de validation de chaîne.

Le code ci-dessous est un exemple fonctionnel de ce que je décris. Je ne sais pas si ce code est acceptable, mais il fonctionne sur des tests de lumière. Toute opinion ou recommandation à ce sujet est la bienvenue dans les commentaires ci-dessous.

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

Je vais laisser cette question ouverte au cas où quelqu'un aurait une meilleure solution pour obtenir ce que j'avais initialement prévu de faire en plus du code ci-dessus.


0 commentaires

3 Réponses :


0
votes

Vous pouvez obtenir l'erreur en appelant directement le middleware imageUpload au lieu de l'utiliser dans une chaîne de middleware comme dans votre code.

Extrait non testé, mais j'espère au moins vous pousser à entrer la bonne direction:

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

Pour en savoir plus sur le sujet, voici les officiels Documentation Multer sur la gestion des erreurs .


2 commentaires

Merci pour la réponse, mais le validateur express ne peut pas lire le corps de la demande tant que Multer n'a pas fait son truc, alors Multer doit être avant le validateur express. Si express-validator s'exécute en premier, le req.body est vide et renvoie simplement des erreurs pour tous les champs de texte. = /


@skaz C'est assez juste, mais je crains que vous n'ayez pas beaucoup de choix avec les erreurs de Multer. Vous devrez utiliser cette façon d'appeler la fonction Multer et valider d'une manière ou d'une autre le texte dans le rappel Multer.



0
votes

Hé, je vais vous laisser avec quelques extraits qui ont fonctionné pour moi,

  • Multer sans utiliser de fichier

    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;
    
  • celui-ci est avec fichier bien que je n'utilise pas de validateur express maintenant, je mettrai à jour cette réponse une fois que cela sera fait

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


0 commentaires

1
votes

J'utilise une fonction qui crée un middleware Multer qui peut être placé n'importe où dans la chaîne middleware. Ensuite, vous pouvez utiliser req.body sans les autres champs binaires.

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

Je gère le req.body avec le package @ hapi / joi npm, mais cela devrait fonctionner avec d'autres validateurs .

note: La raison pour laquelle je n'utilise pas err instanceof multer.MulterError pour vérifier s'il s'agit d'une erreur Multer comme décrit dans la documentation Multer ( https://github.com/expressjs/multer ) est dû à des erreurs de vérification de type de typographie.

p >


1 commentaires

Il y a beaucoup d'autres réponses à cette question (multer + autre middleware + corps du formulaire de lecture) sur SO, et cette solution fait un excellent travail pour résoudre le problème sous-jacent de manière claire et concise. Merci