TASK OF CODE : The code telling multer to save file with pdf extension
PROBLEM : I am getting back error in response but the file getting saved inside the folder
const express = require("express");
const app = new express();
const multer = require("multer");
const upload = multer({
dest: "images", // destination to save the image
limits: 100000, // limiting the size of file to 1mb and 1 mb = 100000bytes
fileFilter(req, file, cb) {
if (!file.originalname.endsWith("pdf")) {
cb(new Error("please upload PDF file extension")); // sending error
}
cb(undefined, true);
// 3 type of call backs
// cb(new Error('please upload PDF file extension'));// sending error
// cb(undefined,true)// undefined means no error and true means accepting file
// cb(undefined,false)// undefined means no error and true means rejecting file
},
});
app.post("/upload", upload.single("upload"), (req, res) => {
res.send();
});
app.listen(8000, () => {
console.log("server fired off");
});
The error message is correct as per what I want
enter image description here
But the file is getting saved in images folder which should not be saved because I am sending jpg extension
Looks like the problem is that the code execution continues after cb(new Error(..), thus cb(undefined,true) gets called as well, telling multer that everything is ok. Change it to:
if (!file.originalname.toLowerCase().endsWith("pdf")) {
return cb(new Error("please upload PDF file extension")); // sending error
}
cb(undefined, true);
Note that I also used .toLowerCase() just to be sure that files with a.PDF extension get uploaded.
I'm making this new function called checkFileType()
function checkFileType(file, cb){
const filetypes = /pdf/;
const extname = filetypes.test(file.originalname.split('.')[file.originalname.split('.').length-1]);
const mimetype = filetypes.test(file.mimetype);
if(mimetype && extname){
return cb(null,true);
}else{
cb(error = 'message : please upload PDF file extension');
}
}
And I implemented it like this
const upload = multer({
dest: "images", // destination to save the image
limits: 100000, // limiting the size of file to 1mb and 1 mb = 100000bytes
fileFilter(req, file, cb) {
checkFileType(file, cb);
},
});
Related
I'm trying to upload a file and store it in an uploads folder, but I get this error: no such file or directory
I get the message success in console but I get this error anyway.
POST /auth/register 500 21.023 ms - 260
Error: ENOENT: no such file or directory, open E:\IMPORTANT\INFO-DEV\DEV\ANGULAR NODEJS\API AUTH\uploads\1671534381494.jpeg
Here is my configuration code for upload.
const path = require("path");
const multer = require("multer");
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "uploads/");
},
filename: function (req, file, cb) {
const extension = path.extname(file.originalname);
cb(null, Date.now() + extension);
},
});
const upload = multer({
storage: storage,
fileFilter: function (req, file, callback) {
if (
file.mimetype == "image/png" ||
file.mimetype == "image/jpg" ||
file.mimetype == "image/jpeg"
) {
callback(null, true);
console.log("Image téléchargé avec succès"); // success message
} else {
callback(null, false);
console.log("Seulement du fichier de type png, jpg ou jpeg"); // error message
}
},
limits: {
fileSize: 1024 * 1024 * 2,
},
});
module.exports = upload;
I got the same error, but I was able to solve it by getting my current path.
import multer from "multer";
// Set up multer storage options
const storage = multer.diskStorage({
destination: function (req, file, cb) {
console.log("🚀 ~ file: upload.ts:11 ~ file", process.cwd());
cb(null, `${process.cwd()}/src/Images`);
},
filename: function (req, file, cb) {
cb(null, file.fieldname + "-" + Date.now());
},
});
// Create a multer instance with the storage options
const upload = multer({ storage });
export default upload;
The issue is that your uploads folder doesn't exist or you set the path incorrectly.
I don't know where exactly you created uploads folder (and if you created it at all).
So in the destination param you should pass either:
path.join(__dirname, '/uploads') - in case that folder is in the same location where current js file is located.
Or path.join(process.cwd(), '/uploads') - in case if uploads folder is in the root of the project (where you run npm start etc.)
So, in short words you need to make sure folder exists and then make sure the path is correct.
P.S.
Using ../../ syntax should also work, you can try ../uploads or ../../uploads if, for example, that folder is on higher levels of your folders structure.
Change this line
cb(null, './uploads/');
this line
cb(null, "uploads/");
or try
cb(__dirname, "uploads/");
you can try your path name as like
img: {
data: fs.readFileSync(
path.join(__dirname + "../../uploads" + req.file.filename)
),
contentType: "image/png",
},
I am creating API using express JS. Now, I have a router which will be used to upload image using multer.
Here is my router :
const multer = require('multer');
module.exports = (app) => {
const DIR = './public/';
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, DIR);
},
filename: (req, file, cb) => {
cb(null , file.originalname);
}
});
const upload = multer({ storage: storage });
// I have also tried this but not working
// const upload = multer({ dest: 'uploads/' });
app.post('/upload', upload.single('image'), (req, res, next) => {
res.status(201).json({
message: "File uploaded successfully"
});
});
}
Now, from my reactjs app I am calling this router using axios like this :
const headers = {
"Content-Type": "multipart/form-data"
}
const body = new FormData();
body.append('image', this.state.selectedCategoryImage);
axios.post('http://localhost:3000/upload', body, { headers }).then((res) => {
console.log(res);
}).catch((err) => {
console.log(err);
});
In above code this.state.selectedCategoryImage is a selected image from html <input> tag.
Now, When I call this api I am getting my response "file uploaded successfully", but I am not able to see my uploaded image anywhere in public directory. My image is not uploading.
Please anyone can help me what's the issue ?
Pass file Object not URL
URL.createObjectURL(file) // it return file url that you can use to show file preview
For upload file, send actual file in axios API as you got from file input
var file = event.target.files[0]; // return actual file
this way it actually send file object.
I'm uploading a file using FormData and receiving it server-side using Multer. Everything works as expected, except since I'm using FileSystem API on the front-end (https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem/webkitGetAsEntry), the files I'm uploading come from sub-directories. Multer seems to only see the filename, even if I explicitly set an alias for the file as I append it to form data (https://developer.mozilla.org/en-US/docs/Web/API/FormData/append). It also seems like Multer performs its logic prior to the rest of my request handler and does not see the parameters I set on the body. How do I get multer to see the full path?
Here is a simplified version of what I currently have setup:
Client (alias represents full name with path, file.name is the base name automatically set by FileSystem API):
function upload(file, alias) {
let url = window.location.origin + '/upload';
let xhr = new XMLHttpRequest();
let formData = new FormData();
xhr.open('POST', url, true);
return new Promise(function (resolve, reject) {
xhr.addEventListener('readystatechange', function(e) {
if (xhr.readyState == 4 && xhr.status == 200) {
resolve(file.name);
}
else if (xhr.readyState == 4 && xhr.status != 200) {
reject(file.name);
}
})
formData.append('file', file, alias || file.name); // this should in theory replace filename, but doesn't
formData.append('alias', alias || file.name); // an extra field that I can't see in multer function at all
xhr.send(formData);
});
}
Server:
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/');
},
filename: function (req, file, cb) {
// neither req nor file seems to contain any hint of the alias here
cb(null, file.originalname);
}
});
const upload = multer({storage: storage});
const bodyParser = require('body-parser');
app.use(bodyParser.json());
app.post('/upload', upload.single('file'), function (req, res, next) {
// by this time the file seems to already be on disk with whatever name multer picked
if (req.file) {
res.status(200).end();
} else {
res.status(500).end();
}
});
In order to get this to work, use the preservePath option when configuring multer. The following will work:
const upload = multer({storage: storage, preservePath: true});
However, it's important to note, multer will not create the directories or subdirectories. Those have to be created beforehand. (I tested this too. If directories are created and empty, upload succeeds, however, if directories do not exist, uploads fail).
In their readme, they say:
"Note: You are responsible for creating the directory when providing destination as a function. When passing a string, multer will make sure that the directory is created for you."
A follow-up to that note would be: "you are responsible for creating any sub-directories too".
The relative paths of files uploaded will be accessible in originalname property. So, backend would look like this: (as you had it, but with updated comments)
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/');
},
filename: function (req, file, cb) {
// If you uploaded for example, the directory: myDir/myFile.txt,
// file.originalname *would* be set to that (myDir/myFile.txt)
// and myFile.txt would get saved to uploads/myDir
// *provided that* uploads/myDir already exists.
// (if it doesn't upload will fail)
// /* if( [ uploads/myDir doesn't exist ] ) { mkdir } */
cb(null, file.originalname);
}
});
Helpful tip:
On the front end, I found it easier to test directory / subdirectory upload with: (tested on Chrome latest ok)
<form action="/uploads/multipleFiles" method="post" enctype="multipart/form-data">
<input type="file" name="multiple" webkitdirectory accept="text/*" onchange="console.log(this.files)" />
<input type="text" name="tester" value="uploadTester" />
<input type="submit"/>
</form>
If you want to upload Passport image as a front and back side then pass parameter from frontend like this user:"username" and type:"front" OR type:"back"
then Use it in node side like this
const upload = multer({
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/passport/');
},
filename: function (req, file, cb) {
cb(null, req.body.user+"-"+req.body.type+".jpg");
}
})
});
I tried to receive the file and store it in the multer storage
Node js code
enter code here
app.post('/createLicence', upload.single('photo'),function(req, res ,next) {
// any logic goes here
console.log("filename" ,req.body.name)
if (!req.file) {
console.log("No file received");
return res.send({
success: false
});
} else {
console.log('file received');
var function_name = 'createLicence'
var arguments_array = [req.file.path,'Raghav','Mumbai','Approved']
invoke = require('/Users/sanjeev.natarajan/fabric-samples/fabcar/invoke.js');
invoke.invokechaincode(function_name,arguments_array)
return res.send({
success: true
})
}
});
but i am receiving no file is receivedi have send the request through postman
-
From : https://www.npmjs.com/package/multer
In order to use the multer package, you have first to define a few parameters so that it can work on your fileDirectory.
In your server.js :
let multer = require('multer');
let storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, '/path/to/storage/')
},
filename: function(req, file, callback) {
callback(null, file.originalname + '-' + Date.now());
}
});
let upload = multer({
storage: storage
});
Now, configure your route
router.route('/your/payload')
.post(authController.isAuthenticated, upload.any(), albumController.postFile)
Note that upload.any() will allow you to upload multiple different formatted files at once. Feel free to use any other kind of upload.method() depending on your needs.
From this point, multer already is doing its job, however you might want to keep track of the files uploaded on your server.
So, in your own module, the logic is pretty much straight forward :
(I'm assuming that you're using mongoose models since you're not giving much information, but that's not the relevant part anyway)
exports.postFile = async (req, res) => {
if (!req || !req.files || !req.files[0]) return res.status(400).send("Bad request.");
for (let i = 0; req.files[i]; i++) {
await File.create({
path: req.files[i],
originalName: req.files[i].originalName,
mimetype: req.files[i].mimetype,
owner: req.user.userId
}, (err, file) => {
if (err) console.log("Something went wrong: " + err); else {
// Do something with file
}
});
}
return res.status(418).send("I'm a teapot.");
}
This configuration and middleware use is ONLY for testing purpose, never ever let anyone upload something to your server without carefully handle that uploading process (file integrity, resource management, ...). An open uploading system can become a very wide backdoor getting straight to your server.
Hope this helps,
regards.
I have big headache to combine angular file upload plugin with multer to make it fully SPA. I stucked on uploading multiple files through multer.
This is how my multer options looks like: (node route.js file)
var upload = multer({
storage: storage,
limits: {
//fileSize: 819200
}
}).array('myFile');
this is my POST: (node route.js file)
router.post('/add/file', function(req, res, next) {
upload(req,res,function(err) {
console.log(req.files);
if(err) {
console.log("Error uploading file.");
}
});
});
this is inside my angular controller:
var uploader = $scope.uploader = new FileUploader({
url: 'http://localhost:3000/add/file',
alias: 'myFile'
});
uploader.filters.push({
name: 'imageFilter',
fn: function(item /*{File|FileLikeObject}*/, options) {
var type = '|' + item.type.slice(item.type.lastIndexOf('/') + 1) + '|';
return '|jpg|png|jpeg|bmp|gif|'.indexOf(type) !== -1;
}
});
It adds only 1st file and stucks - I don't get any error it just stucks - whole page works and I can send files again, but again only 1st file will be uploaded. Console shows that req.files have only 1 file (that first one)
I couldn't find any tutorial or anything on the Internet with angular-file-upload plugin, that's why I ask you guys
Not sure if you figured this out yet or not, but with sending multiple files over, the 'uploadAll' function will not send the next file until it receives a response back from the server. So the route should look like this. I also saw somewhere in the documentation that the response needs to be json...haven't tested whether or not this is true though
router.post('/add/file', function(req, res, next) {
upload(req,res,function(err) {
console.log(req.files);
if(err) {
console.log("Error uploading file.");
} else {
res.status(200).json({response: 'some response...'})
}
});
});