Issue with multer upload files

65 Views Asked by At

I want to upload images on the website built on React. I have issue with backend Node.js code.

Code:

const multer = require("multer");

// Check if the directory exists, if not, create it
const directory = path.join(__dirname, "../src/assets/img/images");

if (!fs.existsSync(directory)) {
    fs.mkdirSync(directory);
}

console.log("Directory: ", directory);

// Set up multer storage and file filter
// Set up multer middleware
const uploadMulter = multer({
    storage: multer.diskStorage({
        destination: (req, file, cb) => {
            cb(null, directory); // Save files to the "src/assets/img/images" directory
        },
        filename: (req, file, cb) => {
            cb(null, file.originalname); // Use the original file name
        }
    }),
    fileFilter: (req, file, cb) => {
        // Accept only image files
        if (file.mimetype.startsWith("image/")) {
            console.log("Success!!!");
            cb(null, true);
        } else {
            console.log("Error!!!!");
            cb(new Error("Invalid file type. Only image files are allowed."));
        }
    }
});

interface FileContent {
  fileName: string;
  content: string;
  type: string;
}

// Route for file upload
app.post("/upload/images", uploadMulter.array("files[]"), (req, res) => {
    // Retrieve the uploaded files from req.files array
    const files = req.files;
    // You can now process the uploaded files (e.g., save to database, manipulate, etc.)
    // For example, if you want to read the content of each file:
    const fileContents: FileContent[] = [];
    files.forEach((file) => {
        console.log("FileError: ", file.fileError);
        console.log("file.fileError.message: ", file.fileError.message);
        const data = fs.readFileSync(file.path, "binary");
        fileContents.push({fileName: file.originalname, content: Buffer.from(data, "binary").toString("base64"), type: file.mimetype}); //, fileError: error
    });

    // Send response
    res.status(200).json({files: fileContents});
});

At this moment, it just prints to the server console. I want to print this error to a user in case a user selects the text file instead of an image:

Invalid file type. Only image files are allowed.

But it fails for me with this error: POST http://localhost:3000/upload/images 500 (Internal Server Error).

Full error log:

Error: Invalid file type. Only image files are allowed.
    at fileFilter (C:\wamp64\www\insurance_site\build_server\server.js:4609:5399)
    at wrappedFileFilter (C:\wamp64\www\insurance_site\node_modules\multer\index.js:44:7)
    at Multipart.<anonymous> (C:\wamp64\www\insurance_site\node_modules\multer\lib\make-middleware.js:107:7)
    at Multipart.emit (events.js:400:28)
    at Multipart.emit (domain.js:475:12)
    at HeaderParser.cb (C:\wamp64\www\insurance_site\node_modules\busboy\lib\types\multipart.js:358:14)
    at HeaderParser.push (C:\wamp64\www\insurance_site\node_modules\busboy\lib\types\multipart.js:162:20)
    at SBMH.ssCb [as _cb] (C:\wamp64\www\insurance_site\node_modules\busboy\lib\types\multipart.js:394:37)
    at feed (C:\wamp64\www\insurance_site\node_modules\streamsearch\lib\sbmh.js:219:14)
    at SBMH.push (C:\wamp64\www\insurance_site\node_modules\streamsearch\lib\sbmh.js:104:16)

Any ideas how to return the proper message back to a user?

2

There are 2 best solutions below

0
Hunter91151 On BEST ANSWER

Ok. I have fixed this issue by removing fileFilterfrom multer. Also, I added checks for image types in the app.post("/upload/images"... method. This will not prevent file from upload to a server but I can display the error message "Invalid file type. Only image files are allowed." to a user and remove file if it's not an image.

Code:

const uploadMulter = multer({
    storage: multer.diskStorage({
        destination: (req, file, cb) => {
            cb(null, directory);
        },
        filename: (req, file, cb) => {
            cb(null, file.originalname);
        }
    })
});

app.post("/upload/images", uploadMulter.array("files[]"), (req, res) => {
    const files = req.files;
    const filteredFiles = files.filter(file => file.mimetype.startsWith("image/"));
    
    if (filteredFiles.length !== files.length) {
        files.forEach((file) => {
          fs.unlink(file.path, (error) => {});
        });

        return res.status(400).json({error: "Invalid file type. Only image files are allowed."});
    }

    const fileContents: FileContent[] = [];
    
    filteredFiles.forEach((file) => {
        const data = fs.readFileSync(file.path, "binary");
        fileContents.push({fileName: file.originalname, content: Buffer.from(data, "binary").toString("base64"), type: file.mimetype, path: file.path, successMsg: "Image(s) uploaded successfully."});
    });

    res.status(200).json({files: fileContents});
});

It works well. This issue is resolved.

2
traynor On

Call the multer middleware from inside route handler, and then check if error is multer's/your file filter's:

// Route for file upload
app.post("/upload/images", (req, res) => {
    
    uploadMulter.array("files[]")(req, res, (err) => {

        if (err instanceof multer.MulterError) {
            return res.status(400).json({ error: err.message });
        } else if (err) {
          // handle multer fileFilter error, or unknown error
            return res.status(400).json({ error: err.message });
        }

        // Retrieve the uploaded files from req.files array
        const files = req.files;
        // You can now process the uploaded files (e.g., save to database, manipulate, etc.)
        // For example, if you want to read the content of each file:
        const fileContents: FileContent[] = [];
        files.forEach((file) => {
            console.log("FileError: ", file.fileError);
            console.log("file.fileError.message: ", file.fileError.message);
            const data = fs.readFileSync(file.path, "binary");
            fileContents.push({fileName: file.originalname, content: Buffer.from(data, "binary").toString("base64"), type: file.mimetype}); //, fileError: error
        });

        // Send response
        res.status(200).json({files: fileContents});
        
    });
   
});

see: Error handling