Multer error cannot upload file with size above 50kb - node.js

I'm having an issue with multer since I'm using socket.io(I'm not sure but after I use this my multer middleware did not work properly). Here is my code for more information
const maxSize = 1024 * 1024 * 2
const storage = multer.diskStorage({
destination: function (_req, _file, cb) {
cb(null, path.join(process.cwd(), 'assets', 'pictures'))
},
filename: function (_req, file, cb) {
const ext = file.originalname.split('.')[1]
const date = new Date()
cb(null, `${date.getTime()}.${ext}`)
}
})
const upload = multer({
storage: storage,
limits: { fileSize: maxSize }
}).single('picture')
const uploadFilter = (req, res, next) => {
console.log(req, 'test mmulter first')
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
return response(res, false, err.message, 400)
} else if (err) {
return response(res, false, err.message, 500)
}
// console.log(req, 'test multer second')
next()
})
}
So when I try to upload a file under 50kb the upload works perfectly, but when I try to put a file with a size of more than 50kb it will keep hanging, no return any response even it no returns an error, so when this error happens the console.log() and next() inside upload not called. The weird thing is the file indeed saved to my local folder (either 50kb or greater) but when it came to the file with size above 50kb it will cropped.
like this
enter image description here

Related

Not able to save image with original name and extension through multer in node.js

Hi I am trying to save an image in my image folder through multer but the issue is that the file is being saved with a randomly generated filename without extension.I have tried to resolve this issue by referring to various articles but still facing the same issue.
referred the following :
Multer is not saving the file as the same name and without extension?
The file gets saved in the image folder like below :
a9bfcba8e950ccfbdaf7f0d2f8d58374
Hence if someone could please help me resolve this issue.
profile.js
const upload = multer({
dest:'images',
filename: function (req, file, cb) {
cb(null, file.originalname)
},
limits: {
fileSize: 10000000,
},
fileFilter(req, file, cb) {
if(!file.originalname.match(/\.(jpg|jpeg|png|JPG|HEIC)$/)) {
return cb(new Error('Please attach an image'))
}
cb(undefined, true);
}
})
router.post('/user/upload', upload.single('profile_pic') , async (req,res) => {
console.log(req.body)
const url = req.protocol + '://' + req.get('host')
//when inserting the file in the database we are able to send the exact location with original file name and extension.
var filepath = url + '/Users/images/';
var reqFiles = (filepath + req.file.filename + path.extname(req.file.originalname)
console.log(req.file);
const notify = new user({
userId: req.body.userId,
profile_pic: reqFiles
})
you need to do step wise process for storing a file.
//storage for image upload
const storage = multer.diskStorage({
destination: './upload',
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
//file filter for extention
let fileFilter = function (req, file, cb) {
console.log(file.mimetype)
const allowedMimes = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'];
if (allowedMimes.includes(file.mimetype)) {
cb(null, true);
} else {
cb(null, false);
}
};
//upload for to pass storage, file size limit and filter
//maximum file size is 10Mb
const upload = multer({
storage: storage,
limits: { fileSize: 10 ** 7 },
fileFilter: fileFilter
}).single('userImage');
then call your route.
router.post('/upload', (req,res)=>{
upload(req, res, (err)=>{
if(err){
console.log(err)
}
else{
console.log(req.file)
console.log(req.file.path)
}
})
})
By following this approach then definitely your error will solved.

how to validate a minimum number of files uploaded with multer?

I want to upload files with multer, but I need that if less than 3 files are loaded simultaneously it shows an error and does not save them on my server. I know how to limit a maximum number of files, but I don't know how to limit a minimum number of files. This is my Multer configuration
const multer = require('multer');
function uploadFile() {
const storage = multer.diskStorage({
destination: './public/files',
filename: function (_req, file, cb) {
var extension = file.originalname.slice(file.originalname.lastIndexOf('.'));
cb(null, Date.now() + extension);
}
});
const upload = multer({
storage,
limits: {fileSize: 11657128, files: 3},
fileFilter: function(req, file, cb) {
let type = req.files
type?cb(null, true):cb(new Error ('no es un archivo de tipo texto plano'));
}}
).array('file');
return upload;
}
module.exports = uploadFile;
You can add a middleware or a validation at your routes.
app.post('/your/route', upload.array('field', 3), function (req, res) {
if (req.files.length !== 3) {
return res.status(400).json({ error: 'Three files is required'})
}
})
With array of middleware:
function validUploadLength (req, res, next) {
if (req.files.length !== 3) {
return res.status(400).json({ error: 'Three files is required'})
}
next()
}
app.post('/your/route', [upload.array('field', 3), validUploadLength], function (req, res) {
/// Your code
})

how to read file from incoming request without saving it to local disk using node.js express?

I have my back-end server in express(node.js) and all apis is running on this server. I also have file-upload mechanism for file-upload api using multer. For file uploading i have created a middleware and in my helper controller i have this
const storage = multer.diskStorage({
destination: (req, file, cb) => {
let path = getFileStoragePath(req, file);
console.log(`path to create ${path}`)
// let path = `uploads/transId${req.body.refrenceId}/transporter`
checkDirectory(path, (err) => {
if (err) {
console.log(`Error occured if checkDirectory ${err.message}`)
cb(err, null)
} else {
cb(null, path);
}
});
},
filename: (req, file, cb) => {
let dateNow = new Date()
cb(null, `${file.fieldname}_${dateformat(dateNow, 'dddd_mmmm_dS_yyyy_h_MM_ss_TT')}${path.extname(file.originalname)}`)
}
});
const saveFilesToFolder = async(req, res, next) => {
const upload = multer({
storage: storage,
fileFilter: imageFilter,
limits: {
fileSize: 1024 * 1024 * 10
}
}).any();
upload(req, res, (err) => {
const wasValidRequest = checkAllowedFiles(req);
if (wasValidRequest.status === false) {
return res.send({
status: false,
message: wasValidRequest.message,
response: null
})
}
// counter = 0
if (err) {
console.log(`Error uploading files, ${err.message}`)
return res.send({
status: false,
message: `Error occurred while uploading files, ${err.message}`,
response: null
})
}
// WHEN FILE UPLOADING IS DONE NOW PASSING THE REQUEST
next();
});
};
And in my route.js file i have attached my middleware to save files into folder and reading files like this
router.post('/upload-files', saveFilesToFolder, catchAsyncErrors(fileController.UploadFiles));
but now my requirement is that i want to read the content of file which is coming in incoming requestwithout saving that file to local disk by accessing the file inside my fileController function and i want to make a separate api for this purpose?
How can i do this
Multer provide memory options by which without storing file in local system, we can convert it into buffer and read the content.
Refer this or this
var storage = multer.memoryStorage();
var upload = multer({ storage: storage });
app.post('/imagenes', upload.single('image_field'), function(req,res){
req.file.buffer;
});
In controller you can use
console.log(String(req.file.buffer))
to look into content
My requirement was to use multer milddleware inside of my controller function to access/read incoming file from request. So i have achieved that and i am giving an answer for future readers so i did like this
controller.js
var storage = multer.memoryStorage({
destination: function(req, file, callback) {
callback(null, '');
}
});
var upload = multer({ storage: storage }).any();
const saveFilesToS3 = async(req, res) => {
upload(req, res, async(err) => {
console.log(req.files[0].buffer) // printing incoming file content as buffer
// rest of the code here
})
}

How to catch errors in multer

I have read documentation for multer. But the current set up I have in my code is different and this makes difficult for me to understand how to handle errors.
It is important now because it happened (only once) that a file was not stored on the server but the code continued saving info in database as if the storing of the file had worked. But it probably did not.
const multer = require('multer');
var docPath = "path_to_disk_where_to_store_files";
var storage = multer.diskStorage({
inMemory: true,
destination: function (request, file, callback) {
callback(null, docPath);
},
filename: function (request, file, callback) {
//Just a function that creates an unique name with timestamp
renamedFile = helpers.createUniqueName(file.originalname);
callback(null, renamedFile);
}
});
var fileFilter = function (req, file, cb) {
var path = require('path');
var ext = path.extname(file.originalname);
if (file.mimetype !== 'application/pdf' || ext.toLowerCase() != '.pdf') {
req.fileValidationError = 'goes wrong on the mimetype';
return cb(null, false, new Error('goes wrong on the mimetype'));
}
cb(null, true);
};
const multerUploader = multer({storage: storage, fileFilter: fileFilter, limits: { fileSize: maxSize }});
router.post('/save_document',[multerUploader.single('file'),saveDocumentInDb]);
I dont really understand where the if-statement that will check if the upload got an error would fit.
Please refer the following for error handling when using multer:
https://github.com/expressjs/multer#error-handling
Your implementation will be something like this:
const multerUploader = multer({storage: storage, fileFilter: fileFilter, limits: { fileSize: maxSize }});
const upload = multerUploader.single('file');
router.post('/save_document', function (req, res) {
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
// A Multer error occurred when uploading.
} else if (err) {
// An unknown error occurred when uploading.
}
// Everything went fine and save document in DB here.
})
})

How to handle erros from multer custom storage?

I'm using multer with sharp and a custom storage, image upload is set and it works fine but I can not handle the errors correctly.
It is crashing my server when I upload for example a wrong file type or when a file is too big.
on my app.js
const upload = multer({
storage: new customStorage({
destination: function(req, file, cb) {
cb(
null,
path.join(
__dirname,
'/images',
new Date().toISOString().replace(/:/g, '-') +
'-' +
file.originalname.replace(/\s+/g, '-')
)
);
}
}),
limits: { fileSize: 5000000 }
});
on my customStorage.js
const fs = require('fs');
const sharp = require('sharp');
const nodePath = require('path');
function getDestination(req, file, cb) {
cb(null, 'images');
}
function customStorage(opts) {
this.getDestination = opts.destination || getDestination;
}
customStorage.prototype._handleFile = function _handleFile(req, file, cb) {
this.getDestination(req, file, function(err, path) {
if (err) return cb(err);//***the problem is here.***
const outStream = fs.createWriteStream(path);
const transform = sharp().resize(200, 200);
file.stream.pipe(transform).pipe(outStream);
outStream.on('error', cb);
outStream.on('finish', function() {
cb(null, {
path: 'images/' + nodePath.basename(path),
size: outStream.bytesWritten
});
});
});
};
customStorage.prototype._removeFile = function _removeFile(req, file, cb) {
fs.unlink(file.path, cb);
};
module.exports = function(opts) {
return new customStorage(opts);
};
When i upload another file it says:
Error: Input buffer contains unsupported image format
Emitted 'error' event at:
at sharp.pipeline (/Users/David/nodejs-app/node_modules/sharp/lib/output.js:687:18)
I would like to handle the errors with express like this instead.
return res.status(422).render('admin/edit-product', {flash message here.}
That's the way I do it with other errors like when the field is empty.
You can throw the error in your Multer custom storage (which is already being done with cb(err) ), and then catch it in a middleware for express.
const upload = multer({
storage: new customStorage({
destination: function(req, file, cb) {
cb(
null,
path.join(
__dirname,
'/images',
new Date().toISOString().replace(/:/g, '-') +
'-' +
file.originalname.replace(/\s+/g, '-')
)
);
}
}),
limits: { fileSize: 5000000 }
});
var uploadMiddleware = function(req, res, next){
var handler = upload.single('media'); //use whatever makes sense here
handler(req, res, function(err){
//send error response if Multer threw an error
if(err){
res.status(500).render('admin/edit-product', "flash message here.");
}
//move to the next middleware, or to the route after no error was found
next();
});
}
Then use the uploadMiddleware in your express route:
app.post('/route/edit', uploadMiddleware, function (req, res) {
//handle request and render normally
});

Resources