Search code examples
node.jsmongodbexpressfilemulter

Multiple File upload Multer middleware working on local server but on server it goes to pending state / hangs after running once


I have a problem with multer middleware. I created the middleware and set the static express files to the uploads folder.

Index.js File

import emailroutes from './routes/emailroutes.js'

app.use(express.json({ limit: '25mb' }));
app.use(express.urlencoded({ extended: false, limit: '25mb' }));
app.use('/uploads', express.static(path.join('uploads')));
app.use('/email', emailroutes);

Then in the routes file, using multer as middleware

import EmailController from '../controller/EmailController.js'
import { storageMultiple } from '../helpers/storage.js'
router.post('/', protect, storageMultiple, EmailController.postEmail)

Multer middle ware function is as follows.

import multer from 'multer';
import md5 from 'md5';
var filepatharray = [];

const diskStorageMultiple = multer.diskStorage({
    destination: (req, file, cb) => {
        cb(null, 'uploads');
    },
    filename: (req, file, cb) => {
        while (i < req.files.length) {
            filepath = md5(Date.now() + i)
            const mimeType = file.mimetype.split('/');
            var fileType = mimeType[1];
            if (fileType == 'vnd.openxmlformats-officedocument.spreadsheetml.sheet') {
                fileType = 'xlsx'
            } else if (fileType == 'text/plain') {
                fileType = 'txt'
            } else if (fileType == 'text/csv') {
                fileType = 'csv'
            } else if (fileType == 'vnd.ms-excel') {
                fileType = 'xls'
            } else if (fileType == 'vnd.openxmlformats-officedocument.wordprocessingml.document') {
                fileType = 'docx'
            } else if (fileType == 'msword') {
                fileType = 'doc'
            } else if (fileType == 'vnd.openxmlformats-officedocument.presentationml.presentation') {
                fileType = 'pptx'
            } else if (fileType == 'vnd.ms-powerpoint') {
                fileType = 'ppt'
            }
            const fileName = filepath + '.' + fileType;
            filepatharray.push({
                path: filepath + '.' + fileType,
                name: file.originalname
            })

            cb(null, fileName);
            i++;
        }
    },
});
const fileFilter = (req, file, cb) => {
    cb(null, true)
};


const storageMultiple = multer({
    storage: diskStorageMultiple,
    fileFilter: fileFilter).array(
    'files'
);

export { storageMultiple , filepatharray}

When i change this to single file upload, it workds fine, Following is the code for multer for single file.

const diskStorage = multer.diskStorage({
    destination: (req, file, cb) => {
        cb(null, './uploads');
    },
    filename: (req, file, cb) => {
        filepath = md5(Date.now() + req.user.id)
        const mimeType = file.mimetype.split('/');
        var fileType = mimeType[1];
        if (fileType == 'vnd.openxmlformats-officedocument.spreadsheetml.sheet') {
            fileType = 'xlsx'
        } else if (fileType == 'text/plain') {
            fileType = 'txt'
        } else if (fileType == 'text/csv') {
            fileType = 'csv'
        } else if (fileType == 'vnd.ms-excel') {
            fileType = 'xls'
        } else if (fileType == 'vnd.openxmlformats-officedocument.wordprocessingml.document') {
            fileType = 'docx'
        } else if (fileType == 'msword') {
            fileType = 'doc'
        } else if (fileType == 'vnd.openxmlformats-officedocument.presentationml.presentation') {
            fileType = 'pptx'
        } else if (fileType == 'vnd.ms-powerpoint') {
            fileType = 'ppt'
        }
        const fileName = filepath + '.' + fileType;
        filepath = filepath + '.' + fileType
        cb(null, fileName);
    },
});
const storage = multer({ storage: diskStorage, fileFilter: fileFilter }).single(
    'file'
);

When i am using multiple files, then i am sending as "files" in multer and when single file, then it is "file"

I am expecting that if someone helps to debug where is the issue on server.


Solution

  • req.files is available after the processing, so there is no point of reading req.files with while loop in filename function, which means you need to remove multiple storage handler completely, and use only single, and determine single and multiple file uploads per route. Try this:

    const storage = multer({ storage: diskStorage, fileFilter: fileFilter })
    
    // single
    router.post('/', protect, storage.single('file'), EmailController.postEmail)
    
    // multiple
    router.post('/', protect, storage.array('files'), EmailController.postEmailWithMultipleFiles)
    

    And if you need filepatharray, you can extract that from req.files

    The difference is that with multiple files, files are stored in req.files, and with single in req.file, so in your case you might not need single at all..