node.js multer module can't handle errors - node.js

I have created a node.js server and i use the multer module for upload some files.
my problem is : how can i handle errors? like if the client close untile the upload is finished? sorry for bad english, i'm italian.
this is my actual don't working code :
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/root/appsistMe/public/AppMeFile/Utenti/'+req.session.nome);
},
filename: function (req, file, cb) {
cb(null, Date.now() + '-' + file.originalname);
}
})
var upload = multer({ storage: storage,
onError : function(err, next) {
console.log('error');
next(err);
}});
app.post('/uploadFile', upload.single('file'), function (req, res, next){
console.log("CI SIAMO AL DOWNLOADDDDDD");
mongo.aggiungiNuovoFile(req, res);
res.status(204).end();
});

onError was removed in version 1.0.0 .
var upload = multer().single('avatar')
app.post('/profile', function (req, res) {
upload(req, res, function (err) {
if (err) {
// An error occurred when uploading
return
}
// Everything went fine
})
})
Please check this link for more details

Related

upload images with nodejs

i have a user.js in model folder
const UserSchema = new mongoose.Schema({
name: {
type: String,
},
profile_pic: {
data: Buffer,
contentType: String
}
})
i want to upload a profile picture
and in the router folder i defined the storage using multer
const storage = multer.diskStorage({
destination: (req, file, callback) => {
callback(null, './images')
},
filename: (req, file, callback) => {
callback(null , Date.now()+ file.originalname)
}
})
const upload = multer({
storage : storage,
limits : {
fieldSize : 1024*1024*3
}
})
router.post('/image' , upload.single('image'),image)
using postman i tried to upload an image .. it uploaded successfully and stored in the defined folder (images)
but i want to store the image in the model too
how to store it in the controller folder user.js
Try the example below
const app = require("express")();
const multer = require('multer')
const firstLocation = multer.diskStorage({
destination: function (req, file, cb) {');
cb(null, './imagesFolder/')
},
filename: (req, file, callback) => {
callback(null , Date.now()+ file.originalname)
}
});
const secondLocation = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, './modelFolder/')
},
filename: (req, file, callback) => {
callback(null , Date.now()+ file.originalname)
}
});
const firstPath = multer({ storage: firstLocation })
const secondPath = multer({ storage: secondLocation })
function fileUpload(req, res, next) {
firstPath.single('file')(req, res, next);
secondPath.single('file')(req, res, next);
next();
}
app.post("/", fileUpload, (req, res) => {
res.send("Received file");
});
app.listen(3000, () => {
console.log("Server started");
});
If you run the above code and send a request to localhost:3000 then you will notice that two directories created named imagesFolder and modelFolder. Inside those folders, you will see the file that you have uploaded.
Updated answer in response to comments for Mongo schema,
const imagePath = '/path/to/myImage.jpg';
const imageUp = mongoose.model('imageUp', UserSchema);
mongoose.connection.on('open', function () {
imageUp.remove((err) => {
if (err) throw err;
const up = new imageUp;
up.img.data = fs.readFileSync(imagePath); // read from you folder
up.img.contentType = 'image/jpg'; // set the content tpe to image format
up.save((err, a) => { // save or upload image
if (err) throw err; // throws error if anything goes wrong
app.get('/', (req, res, next) => {
imageUp.findById(up, (err, doc) => { // fetch image from db by id and send in response as required.
if (err) return next(err);
res.contentType(doc.img.contentType);
res.send(doc.img.data);
});
});
}
Ref:- https://www.geeksforgeeks.org/upload-and-retrieve-image-on-mongodb-using-mongoose/

How to use Multer to upload a file in two different directories?

I'm new in using nodejs and multer and I want to upload an image but in two different directories. I tried using two different middleware but since the first multer function returns a file destination I couldnt use it to upload in the other multer function. Is it possbile to upload a file using multer in two different directories?
Create multiple storages and call them at the same time.
Example:
const app = require("express")();
const multer = require('multer');
const storageA = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './storageA/');
},
filename: function (req, file, cb) {
cb(null, file.originalname);
}
});
const storageB = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './storageB/');
},
filename: function (req, file, cb) {
cb(null, file.originalname);
}
});
const destA = multer({ storage: storageA });
const destB = multer({ storage: storageB });
function fileUpload(req, res, next) {
destA.single('file')(req, res, next);
destB.single('file')(req, res, next);
}
app.post("/", fileUpload, (req, res) => {
res.json({ file: req.file });
});
app.listen(3000, () => {
console.log("Server started");
});
The uploaded file will be store in ./storageA and ./storageB.
This is not an official way, but went I try it, it works!

Error when uploading files using FilePond and multer (expressjs)

I've written a react app that makes use of the FilePond file uploader but am having trouble getting multer to accept the request from filepond, it always returns a 500 error.
If I use a standard file upload control the request is accepted by the server and the file uploads fine.
Does anyone have any thoughts on what might be causing this?
Thanks
This is my server.js code:
var express = require('express');
var app = express();
var multer = require('multer')
var cors = require('cors');
app.use(cors())
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'public')
},
filename: function (req, file, cb) {
cb(null, Date.now() + '-' +file.originalname )
}
})
var upload = multer({ storage: storage }).array('file')
app.get('/',function(req,res){
return res.send('Hello Server')
})
app.post('/upload', function(req, res) {
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
return res.status(500).json(err)
// A Multer error occurred when uploading.
} else if (err) {
return res.status(500).json(err)
// An unknown error occurred when uploading.
}
res.send([req.files[0].filename]);
return res.status(200).send(req.file)
// Everything went fine.
})
});
app.listen(8000, function() {
console.log('App running on port 8000');
});

Same Image not uploading in express

I am trying to upload an image using express but I am facing two problems, first, whenever I upload the same image again it's not getting uploaded and secondly after uploading any single image a file with image also uploading. Here is my code.
var multer = require('multer');
var uploads = multer({dest: './images'});
app.post('/uploading', uploads.single("file"), function (req, res) {
var file = __dirname +"/images" + "/" + req.file.originalname;
fs.readFile( req.file.path, function (err, data) {
fs.writeFile(file, data, function (err,data) {
if( err ){
console.error( err );
response = {
message: 'Sorry, file couldn\'t be uploaded.',
filename: req.file.originalname
};
}else{
response = {
message: 'File uploaded successfully',
filename: req.file.originalname
};
}
res.end( JSON.stringify( response ) );
});
});
})
The uploads.single("file") middleware Will handle the file upload. You don't have to specifically fs.read and fs.write the file.
var multer = require('multer');
var uploads = multer({dest: './images'});
app.post('/uploading', uploads.single("file"), function (req, res) {
//the file is uploaded automatically
})
EDIT: The above code will upload the file with hex string as filename without any extension.
In order to add rename function you need to use diskStorage. Here is the code taken from this github issue page.
var multer = require('multer');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './images/')
},
filename: function (req, file, cb) {
crypto.pseudoRandomBytes(16, function (err, raw) {
cb(null, raw.toString('hex') + Date.now() + '.' + mime.extension(file.mimetype)); //this is the rename func
});
}
});
var uploads = multer({ storage: storage });
app.post('/uploading', uploads.single("file"), function (req, res) {
//the file is uploaded automatically
})
Now you can use the uploads variable as middleware as shown in the above snippet.
you can edit the filename: function (req, file, cb) { .. } according to your needs. Now the filename will be, <16characterhexstring>.ext
another way to handle it will be not using middleware and using multer manually with below options :
try {
var storage = multer.diskStorage({
destination: function(request, file, callback) {
//define folder here by fs.mkdirSync(anyDirName);
},
filename: function(req, file, callback) {
callback(null, anyFileName);
},
limits: self.limits
});
var upload = multer({
storage: storage,
fileFilter: function(request, file, callback) {
// here you can filter out what not to upload..
}
}).any();
upload(request, response, callback);
} catch (e) {
}
hope this helps!

Error handling when uploading file using multer with expressjs

I am using multer to save the file on server developed through express & nodejs.
I am usign following code.
var express = require('express'),
multer = require('multer')
var app = express()
app.get('/', function(req, res){
res.send('hello world');
});
app.post('/upload',[ multer({ dest: './uploads/'}), function(req, res){
res.status(204).end()
}]);
app.listen(3000);
Multer saves the file for me in the specified destination folder.
All this is working fine but I have following questions:
If the file saving fails for various reasons, it looks like my route will always return status 204.
I am not sure if status 204 is retured after file is saved or while the file is getting saved asynchronously, status 204 is returned.
This is how to write multer middleware that handle upload and errors
const multer = require("multer");
function uploadFile(req, res, next) {
const upload = multer().single('yourFileNameHere');
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.
next()
})
}
You can handle errors using the onError option:
app.post('/upload',[
multer({
dest : './uploads/',
onError : function(err, next) {
console.log('error', err);
next(err);
}
}),
function(req, res) {
res.status(204).end();
}
]);
If you call next(err), your route handler (generating the 204) will be skipped and the error will be handled by Express.
I think (not 100% sure as it depends on how multer is implemented) that your route handler will be called when the file is saved. You can use onFileUploadComplete to log a message when the upload is done, and compare that to when your route handler is called.
Looking at the code, multer calls the next middleware/route handler when the file has been uploaded completely.
Try this
var upload = multer().single('avatar')
app.post('/profile', function (req, res) {
upload(req, res, function (err) {
if (err) {
// An error occurred when uploading
return
}
// Everything went fine
})
}
ref :
http://wiki.workassis.com/nodejs-express-get-post-multipart-request-handling-example/
https://www.npmjs.com/package/multer#error-handling
As you can see from the code below (the source from the muter index.js file), if you not pass the onError callback the error will be handled by express.
fileStream.on('error', function(error) {
// trigger "file error" event
if (options.onError) { options.onError(error, next); }
else next(error);
});
Be careful with the system when the user sends anything to you
I usually set more [*option1]:
process.on('uncaughtException', function(ls){
// console.log(ls);
(function(){})();
});
And then:
var upload= multer({ dest: __dirname + '/../uploads/' }).single('photos');
// middle ..
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
// A Multer error occurred when uploading.
console.log('MulterError', err);
} else if (err) {
// An unknown error occurred when uploading.
// Work best when have [*option1]
console.log('UnhandledError', err);
}
if(err) {
return res.sendStatus(403);
}
res.sendStatus(200);
});
package: "multer": "^1.4.2"
var multer = require('multer')
var upload = multer().single('avatar')
app.post('/profile', function (req, res) {
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
handle error
} else if (err) {
handle error
}
else{
write you code
}
})
})
you can see this from the documentation
According to the multer documentation (https://github.com/expressjs/multer#error-handling)
Error handling
When encountering an error, Multer will delegate the error to Express. You can display a nice error page using the standard express way.
If you want to catch errors specifically from Multer, you can call the middleware function by yourself. Also, if you want to catch only the Multer errors, you can use the MulterError class that is attached to the multer object itself (e.g. err instanceof multer.MulterError).
code sample
const multer = require('multer')
const upload = multer().single('avatar')
app.post('/profile', 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.
})
})
When we re-write the code in this question with latest version of multer (v1.4.5-lts.1)
const express = require('express');
const multer = require('multer');
const app = express();
const upload = multer({ dest: './uploads/' }).single('fieldName');
app.get('/', (req, res) => {
res.send('hello world');
});
app.post(
'/upload',
(req, res, next) => {
upload(req, res, (err) => {
if (err instanceof multer.MulterError) {
res.status(404).send(err + 'Upload failed due to multer error');
} else if (err) {
res.status(404).send(err + 'Upload failed due to unknown error');
}
// Everything went fine.
next();
});
},
(req, res) => {
res.status(204).end();
}
);
app.listen(3000);
To check the Multer errors and non multer errors we can add validations using fileFilter and limits
eg:
I am adding a CSV file filter method and some limits
// CSV file filter - will only accept files with .csv extension
const csvFilter = (req, file, cb) => {
console.log('csv filter working');
if (file.mimetype.includes('csv')) {
cb(null, true);
} else {
cb('Please upload only csv file.', false);
}
};
// adding the csv file checking, file number limit to 1 and file size limit 10 1kb
const upload = multer({
dest: './uploads/',
fileFilter: csvFilter,
limits: { files: 1, fileSize: 1024 }
}).single('fieldName');
We can see different errors are thrown when we try to upload non CSV file or >1kb sized file or multiple files.
I know its late but it might help others.
Here is how I handle errors and use it safely in my express/typescript
project.
const upload = (fieldName: string) => {
return (req: Request, res: Response, next: NextFunction) => {
return multer({
storage: multer.diskStorage({
destination: (req, file, cb) => {
if (file.fieldname === 'post') {
return cb(null, `${path.join(path.dirname(__dirname), 'uploads/postImg')}`);
} else if (file.fieldname === 'profile') {
return cb(null, `${path.join(path.dirname(__dirname), 'uploads/ProfilePic')}`);
} else {
return cb(new Error(`${file.fieldname} is incorrect`), null);
}
},
filename: (req, file, cb) => {
return cb(null, `${file.originalname}-${Date.now()}-${file.fieldname}`);
},
}),
fileFilter: (req, file, cb) => {
const fileExtension = file.mimetype.split('/')[1];
if (!(fileExtension in allowedFiles)) return cb(null, false);
return cb(null, true);
},
dest: `${path.join(path.dirname(__dirname), 'uploads')}`,
limits: {
fileSize: 1024 * 1024 * 3, // 3MB
files: 1,
},
}).single(fieldName)(req, res, (err: any) => {
if (err instanceof multer.MulterError) {
// handle file size error
if (err.code === 'LIMIT_FILE_SIZE') return res.status(400).send({ error: err.message });
// handle unexpected file error
if (err.code === 'LIMIT_UNEXPECTED_FILE') return res.status(400).send({ error: err.message });
// handle unexpected field key error
if (err.code === 'LIMIT_FIELD_KEY') return res.status(400).send({ error: err.message });
}
next();
});
};
};
app.post("/upload", (req: Request, res:Response)=>{
res.json({message:"file uploaded"})
})

Resources