skip to Main Content

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:wamp64wwwinsurance_sitebuild_serverserver.js:4609:5399)
    at wrappedFileFilter (C:wamp64wwwinsurance_sitenode_modulesmulterindex.js:44:7)
    at Multipart.<anonymous> (C:wamp64wwwinsurance_sitenode_modulesmulterlibmake-middleware.js:107:7)
    at Multipart.emit (events.js:400:28)
    at Multipart.emit (domain.js:475:12)
    at HeaderParser.cb (C:wamp64wwwinsurance_sitenode_modulesbusboylibtypesmultipart.js:358:14)
    at HeaderParser.push (C:wamp64wwwinsurance_sitenode_modulesbusboylibtypesmultipart.js:162:20)
    at SBMH.ssCb [as _cb] (C:wamp64wwwinsurance_sitenode_modulesbusboylibtypesmultipart.js:394:37)
    at feed (C:wamp64wwwinsurance_sitenode_modulesstreamsearchlibsbmh.js:219:14)
    at SBMH.push (C:wamp64wwwinsurance_sitenode_modulesstreamsearchlibsbmh.js:104:16)

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

2

Answers


  1. Chosen as 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. 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

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search