I'm using Multer to upload jpg file from Postman to a node.js back-end.
I assume the "upload" goes well because the image is located at the right place with the right name and the right size after the POST request
Unfortunately, when I try to open the image file it doesn't open as a jpg image even though the extension is .jpg
I used checkFileType website and apparently, the file type becomes application/octet-stream after the upload.
I didn't specify any headers in the request.
Here is my Postman setup
Here is the response
Here is the code in the Node API side
var localWorkLocation = '/Users/noste/CarFixer/Pictures/';
exports.createBinary = function (req, res) {
var location = localWorkLocation + req.params.platenumber;
var storageOptions = multer.diskStorage({
destination: function (req, file, callback) {
mkdirp(location, err => callback(err, location));
callback(null, location);
},
filename: function (req, file, callback) {
//if (!file.originalname.match(/\.(jpg|jpeg|png)$/)) {
// return callback(new Error('Only image files are allowed!'), false);
//}
callback(null, file.originalname);
},
});
var upload = multer({storage : storageOptions}).single('picture');
upload(req, res, function(err){
console.log(req.file);
if(err) {
return res.end(err.message);
}
res.send(req.file);
});
};
I've tried to upload a .txt file and it's still readable after upload.
Is there a place where I need to specify that I want to keep the jpg format ?
here's the storage configuration u need .. change the naming according to your code
var path = require('path');
var storage = multer.diskStorage({
destination: function(req, file, callback) {
callback(null, './uploads');
},
filename: function(req, file, callback) {
var fname = file.fieldname + '-' + Date.now() + path.extname(file.originalname);
callback(null, fname);
}
});
And here's another answer for multiple files upload
Related
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.
I want to send some image file from one Nodejs server to another Nodejs server. And how to get the file in second server? Also how to save into a folder in second server?
How to do that any suggestion?
First server
uploadImage(req, callback) {
var formData = new FormData();
var body = {
"file": req.file,
}
var options = {
'method': 'POST',
'url': config.db_layer_endpointUpload,
'headers': {
'api_key': config.db_layer_access_key,
'content-type': 'application/json'
},
body: JSON.stringify(body),
}
request(options, function (error, response) {
return callback(response.body);
})
}
Second server
app.post(
"/upload",
multerObj.single("file"),
(req, res) => {
console.log(req.body);
}
);
When console.log i am getting following result in Second server file
But Image is not saved in the asset folder. Multer and storage are fine. When i uploaded Image to Second server directly its working fine.
The first thing you need to do is create an API using node/Express.js and create store using multer:
const storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, 'uploads/');
},
// By default, multer removes file extensions so let's add them back
filename: function(req, file, cb) {
cb(null, file.fieldname + '-' + Date.now() +
path.extname(file.originalname));
}
});
Build the image filter function:
const imageFilter = function(req, file, cb) {
// Accept images only
if (!file.originalname.match(/\.(jpg|JPG|jpeg|JPEG|png|PNG|gif|GIF)$/)) {
req.fileValidationError = 'Only image files are allowed!';
return cb(new Error('Only image files are allowed!'), false);
}
cb(null, true);
};
exports.imageFilter = imageFilter;
Create an API to handle image get from request:
app.post('/upload-pic', (req, res) => {
let upload = multer({ storage: storage, fileFilter: helpers.imageFilter }).single('pic');
upload(req, res, function(err) {
// req.file contains information of uploaded file
// req.body contains information of text fields, if there were any
if (req.fileValidationError) {
return res.send(req.fileValidationError);
}
else if (!req.file) {
return res.send('Please select an image to upload');
}
else if (err instanceof multer.MulterError) {
return res.send(err);
}
else if (err) {
return res.send(err);
}
// Display uploaded image for user validation
res.send(`You have uploaded this image`);
});
});
Now you have the server side accept the image from request and save it on file. After that, let us go back to the other server. On other server it's like a client and we need create request to the API upload-pic . To do that you can use axios package and form-data package.
Handling File Uploads
In cloudinary I have a folder called images, I want to upload the files into that folder.
I have done set up the cloudinary config. The storage options and the file filter has been done. In the request, I send the post request that will upload the file to cloudinary, but not to the folder. How can I upload a file to a certain folder in Cloudinary?
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, './images/');
},
filename: (req, file, cb) => {
cb(null, new Date().toISOString().replace(/:/g, '-') + file.originalname);
}
});
const fileFilter = (req, file, cb) => {
if (!file.mimetype.match(/jpe|jpeg|png|gif$i/)) {
cb(new Error('File is not supported'), false);
return;
}
cb(null, true);
};
const upload = multer({
storage,
fileFilter
});
router.post('/', upload.single('profileImage'), async (req,res) => {
const result = await cloudinary.v2.uploader.upload(req.file.path);
})
When you're performing the upload request you can specify a set of options to be used for that upload. In these options, you can specify the 'public_id' (filename) and/or 'folder' of where the file should be stored.
For example, to upload a file to a folder called 'test', you can use the code below:
cloudinary.v2.uploader.upload(
"path/to/file",
{
folder: "test",
},
function(error, result) {
console.log(error,result);
}
);
You can find out all available options for the upload method via this section of the documentation:
https://cloudinary.com/documentation/image_upload_api_reference#upload_method
I am writing a node application and I was looking for something to upload files on the server. I could get files to upload when there was only one static directory. But I need to make directories per user and then upload files to those, according to the user that's logged in. I looked stuff up but everything that I try ends in an Error: ENOENT: no such file or directory, open ... error. What I am trying to do currently is this -
let storage = multer.diskStorage({
destination: function(req, file, cb) {
let dest = path.join(__dirname, './documents', 'somenameigetfromtheuser');
let stat = null;
try {
stat = fs.statSync(dest);
}
catch (err) {
fs.mkdirSync(dest);
}
if (stat && !stat.isDirectory()) {
throw new Error('Directory cannot be created');
}
cb(null, dest);
}
});
let upload = multer({
storage: storage,
dest: 'documents/'
});
app.post('/testUpload', upload.single('testfile'), (req, res) => {
res.json({
test: 'test'
})
});
There is a similar question that has been answered but it doesn't work that way for me because I want the directory name from the request object.
When I remove the storage property in my multer initialization, the files are stored in the documents directory with a random name. I want the file to have its original name and I want it to be stored in a directory where I get the name of the directory from the req object.
Help a brother out, thanks!
edited
See https://github.com/expressjs/multer#diskstorage
Note that req.body might not have been fully populated yet. It depends on the order that the client transmits fields and files to the server.
Due to that, first write file in temp directory, read directory name from req and move file:
fs = require('fs-extra'); //npm install fs.extra
...
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '../tempDir/')
},
filename: function (req, file, cb) {
cb(null, file.originalname)
}
});
var upload = multer({
storage: storage
}).single('file');
upload(req, res, function (err) {
if (err) {
res.json({});
return;
}
var dir = JSON.parse(req.body.data).directory;
var filename = req.file.filename;
fs.move('../tempDir/' + fileName, '../tempDir/' + dir + '/' + fileName, function (err) {
if (err) {
return console.error(err);
}
res.json({});
});
});
Here's code for dynamic path by argument!
exports.upload = (folderName) => {
return imageUpload = multer({
storage: multer.diskStorage({
destination: function (req, file, cb) {
const path = `src/assets/uploads/${folderName}/`;
fs.mkdirSync(path, { recursive: true })
cb(null, path);
},
// By default, multer removes file extensions so let's add them back
filename: function (req, file, cb) {
cb(null, Date.now() + path.extname(file.originalname));
}
}),
limits: { fileSize: 10000000 },
fileFilter: function (req, file, cb) {
if (!file.originalname.match(/\.(jpg|JPG|webp|jpeg|JPEG|png|PNG|gif|GIF|jfif|JFIF)$/)) {
req.fileValidationError = 'Only image files are allowed!';
return cb(null, false);
}
cb(null, true);
}
})
}
and call it
Make sure you append first the textfields on the client-side and only then do you append the files. In my case i had something like this:
`
for(let i=0; i<files.length;i++)
{
formData.append("files[]",files[i]);
}
formData.append("username",username);
`
The fix was to first append the textfield like so:
`
formData.append("username",username);
for(let i=0; i<files.length;i++)
{
formData.append("files[]",files[i]);
}
`
Here's what I do for uploading files to dynamic directories.
In frontend I use URL parameters to pass user IDs.
await axios({
method: 'post',
data: formData,
url: '/api/upload?userId=123',
headers: { 'content-type': 'multipart/form-data' }
})
In backend get that parameter and use for destination. Also create the directory if it doesn't exist.
const upload = multer({
storage: multer.diskStorage({
destination: (req, file, cb) => {
const directory = `./public/uploads/${req.query.userId}`
if (!fs.existsSync(directory)) {
fs.mkdirSync(directory, { recursive: true })
}
cb(null, directory)
},
filename: (req, file, cb) => {
cb(null, `${Date.now()}-${file.originalname}`)
}
})
})
In my project I use multer as follow:
1.Store the file first in a common directory, like /tmp/.
2.Copy/move the file anywhere you want, to CDN in my case, and to a user folder in yours.
3.Remove the original file in /tmp if needed.
And maybe let upload = multer({
storage: storage,
dest: 'documents/'
}); you should remove the dest here since you specified dest in storage, right?
const storage = multer.diskStorage({
destination: function(req, file, callback){
callback(null, path.dirname('D:/') + 'Integra Qamba Site/');
},
filename: function(req, file, callback){
let data = new Date();
callback(null, dateTime +".jpg");
}
});
I'm performing a file upload via multer, and since I want to store the file in a specific location, as well as name it my own file name, I am using the destination and filename attributes that multer offers when creating the storage object.
The problem I'm having is I want to send back to the client the information of my newly created object after storing it in the database. However, there is no res parameter to do this and I can only do this in my post method, which does not have the object I just created.
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads'); // Absolute path. Folder must exist, will not be created for you.
},
filename: function (req, file, cb) {
var fileType = file.mimetype.split("/")[1];
var fileDestination = file.originalname + '-' + Date.now() + "." + fileType;
cb(null, fileDestination);
var map = new Map({
mapName: req.body.mapTitle,
mapImagePath: "./uploads/" + fileDestination,
ownerId: req.user._id
});
Map.createMap(map, function(err, map){
if(err)
next(err);
console.log(map);
});
}
});
var upload = multer({ storage: storage });
router.post('/', upload.single('mapImage'), function (req, res) {
res.status(200).send({
code: 200, success: "Map Created."
});
});
Multer attaches the files to the request object, you have access to these in your post method:
app.post('/', upload.single('mapImage'), function (req, res, next) {
console.log(req.file.filename); // prints the filename
console.log(req.file.destination); // prints the directory
console.log(req.file.path); // prints the full path (directory + filename)
console.log(req.file.originalname); // prints the name before you renamed it
console.log(req.file.size); // prints the size of the file (in bytes)
res.json(req.file);
});