Vishnu
Vishnu

Reputation: 755

How to catch the error when i am using file filter in multer?

I have searched but i couldn't find exact solution..When i uploading image it should allow only jpg,jpeg,gif,png..If any other file it should show message in UI. I have used the following code

var upload = multer({ storage: storage,
 fileFilter: function (req, file, cb) {
        var ext = path.extname(file.originalname);
        if(ext !== '.png' && ext !== '.jpg' && ext !== '.gif' && ext !== '.jpeg') {
             return cb(new Error('Wrong extension type'));
            // if(Error){
            //     console.log("error file type")
            // }

        }
        cb(null, true)
    }

});

If i try to upload pic rather than jpeg,jpg,png,git It showing error ..But how to display as message in my application page itself

Error: Wrong extension type
    at fileFilter (D:\Vishnu\octopus new\app\routes.js:912:24)
    at wrappedFileFilter (D:\Vishnu\octopus new\node_modules\multer\index.js:44:7)
    at Busboy.<anonymous> (D:\Vishnu\octopus new\node_modules\multer\lib\make-middleware.js:114:7)
    at emitMany (events.js:127:13)
    at Busboy.emit (events.js:201:7)
    at Busboy.emit (D:\Vishnu\octopus new\node_modules\busboy\lib\main.js:38:33)
    at PartStream.<anonymous> (D:\Vishnu\octopus new\node_modules\busboy\lib\types\multipart.js:213:13)
    at emitOne (events.js:96:13)
    at PartStream.emit (events.js:188:7)
    at HeaderParser.<anonymous> (D:\Vishnu\octopus new\node_modules\dicer\lib\Dicer.js:51:16)
    at emitOne (events.js:96:13)
    at HeaderParser.emit (events.js:188:7)
    at HeaderParser._finish (D:\Vishnu\octopus new\node_modules\dicer\lib\HeaderParser.js:68:8)
    at SBMH.<anonymous> (D:\Vishnu\octopus new\node_modules\dicer\lib\HeaderParser.js:40:12)
    at emitMany (events.js:127:13)
    at SBMH.emit (events.js:201:7)

Kindly help me in this issue.. Thanks in Advance

Upvotes: 3

Views: 9932

Answers (5)

Akhil Chandran
Akhil Chandran

Reputation: 198

const fileTypes = /jpeg|JPEG|jpg|JPG|png|PNG|gif|GIF/;
const mimetype = fileTypes.test(file.mimetype);

if (mimetype) {
   return cb(null, true);
}else{
  req.fileValidationError = "Your Error Message";
  return cb(null, false, req.fileValidationError);
  // if the above code is not working, try this:
  return cb(req.fileValidationError, false);
}   

Upvotes: 0

Pallav Chanana
Pallav Chanana

Reputation: 667

Alternate way to handle exceptions with the help of middleware

router.post("/v1/user/create",uploadFile,customBadRequestException,customBadFileRequestException)

Custom exceptions

exports.customBadRequestException = (req,res,next) => {
  if(!req.body || !req.body.data || !req.body.data.length || !req.file || !req.file.filename){
    return res.status(400).send({ message: "Bad request" });
  }
  next();
};

exports.customBadFileRequestException = (req,res,next) => {
  if (! /\.(jpe?g|png|gif|bmp)$/i.test(req.file.filename)) {
    return res.status(400).send({ message: "Please upload only images" });
  } 
  next();
};

Multer Config

const multer = require("multer");
    var storage = multer.diskStorage({
      destination: (req, file, cb) => {
        cb(null,"/Users/path/Desktop/testFiles");
      },
      filename: (req, file, cb) => {
        cb(null, `${Date.now()}-${file.originalname}`);
      },
    });
    
    var uploadFile = multer({ storage: storage}).single("file");
    module.exports = uploadFile;

Upvotes: 0

turivishal
turivishal

Reputation: 36104

fileFilter callback should be:

var upload = multer({ 
    storage: storage,
    fileFilter: function (req, file, cb) {
        var ext = path.extname(file.originalname);
        if(ext !== '.png' && ext !== '.jpg' && ext !== '.gif' && ext !== '.jpeg') {
            cb(new Error('Wrong extension type'), false);
        }
        cb(null, true)
    }
});

Error handling in request:

  • access multer error using MulterError
const multer = require("multer");

router.post('/upload', function(req, res) {
    upload.single('field name')(req, res, function(err) {

        // FILE SIZE ERROR
        if (err instanceof multer.MulterError) {
            return res.end("Max file size 2MB allowed!");
        }

        // INVALID FILE TYPE, message will return from fileFilter callback
        else if (err) {
            return res.end(err.message);
        }

        // FILE NOT SELECTED
        else if (!req.file) {
            return res.end("File is required!");
        }
 
        // SUCCESS
        else {
            console.log("File uploaded successfully!");
            console.log("File response", req.file);
        }

    )}
})

Upvotes: 2

FS_woods
FS_woods

Reputation: 33

Adding to this answer, which works like a charm by the way.

If you want a catch-all for errors that result from a file not accepted by MIME type or because a file was not attached, you can do the following:

Set your FileFilter function to something like this:

const upload = multer({
storage: //storage declaration here,
fileFilter: (req, file, cb) => {
        if (
            !file.mimetype.includes("image/png") &&
            !file.mimetype.includes("image/jpeg")
        ) {
            return cb(null, false);
        }
        cb(null, true);
    }
});

and then in your route or wherever your req, res is scoped, you can catch the error and respond accordingly by checking the req.file variable that normally holds the uploaded file information:

if (!req.file) {
            console.log("No file received or invalid file type");
            return res.status(400).send({
                message: "No file received or invalid file type",
                success: false
            });
}

Without setting a new req variable to hold a ValidationError, you can respond gracefully to the user if they don't provide a valid file.

This works because the FileFilter will successfully filter out a file that doesn't match your validation even without throwing an error in the callback, but instead of throwing an error, it just won't proceed with accepting the file. I don't understand fully why the callback in multer is built that way as the method of throwing errors does not bubble up to your route or controller.

With the above code, however, if the fileFilter does its job, when you check that req.file exists (or doesn't in this case) with if(!req.file){}, you can catch both no-file submissions and failed validation at once without the messy error that gets thrown from fileFilter's callback :)

Upvotes: 2

guest1234
guest1234

Reputation: 228

I've been struggling with this problem for a while now as well. I thought I had found one solution but it ended up not working that well for me but after enough tinkering and looking around tonight I found an answer that works for me. I hope this helps. I actually found this question while looking around for an answer.

So what I did was created req.fileValidationError in your example as so:

var upload = multer({ 
     fileFilter: function (req, file, cb) {
          let ext = path.extname(file.originalname);
          if (ext !== '.png' && ext !== '.jpg' && ext !== '.gif' && ext !== '.jpeg') {
               req.fileValidationError = "Forbidden extension";
               return cb(null, false, req.fileValidationError);
         }
         cb(null, true);
     }
});

Then in your route you want to check req.fileValidationError with an if statement. If it exists then you know there is a forbidden extension.

Assuming you are using express under the app variable, and you are wanting single images to be sent, it would look something like so:

app.post('/your-upload-route', upload.single("your-input-name-here"), function(req, res) {
     if (req.fileValidationError) {
          // return res.sendFile();
          // or return res.end();
          // or even res.render(); whatever response you want here.
     }
});

I hope this helps! If anyone else has a different way of doing this I'd be happy to update my answer as well as seeing other people's insight.

Upvotes: 19

Related Questions