I have seen many answers on this and tried almost all of it but none seems to work for me. I can print the form data as ascii chars but I don't see the file stored in the public/uploads folder as expected. I can read and render stored files on react app using API but can't upload it. I get no errors, everything works fine but no file is uploaded in the folder. I'm trying to upload a file using multer and below are the code snippets :
routes/uploads.js
var storage = multer.diskStorage({
dest : function (req, file, cb) {
cb(null, path.join(__dirname, 'public/uploads/'))
}
});
var upload = multer({storage:storage}) ;
router.post('/upload', upload.single('mypic'), function (req, res, next) {
console.log("inside upload files");
console.log(req.body); //prints non-readable characters as I am uploading image as expected
console.log(req.file); //says undefined
return res.status(204).end();
});
API.js (React side):
export const uploadFile = (payload) => //payload is actually formdata
fetch(`${api}/files/upload`,
{
method: 'POST',
//headers: { 'Content-Type': 'application/json' },
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
},
body: payload
}
)
.then(res => {
console.log(res);
return res.status;
})
.catch(error => {
console.log(error);
return error;
});
Try below IT contains multiple parts:
var storage = multer.diskStorage({
destination: function (req, file, cb) {
const extension = file.mimetype.split('/')[1];
//you can change destination runtime
if(file.fieldname == "covers[]")
{
cb(null, __dirname, '../public/uploads/cover');
return;
}
else
{
cb(null, '../public/uploads/image');
return;
}
},
filename: function (req, file, cb) {
//you can also change name
cb(null, filename)
}
});
var upload = multer({
storage: storage,
});
Try removing :
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
Related
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
This multer configuration lets me upload images with '.gif' format. How to solve this ? I want it to only upload png, jpg, jpeg
This is my code:
let storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/public/images')
},
filename: function (req, file, cb) {
crypto.pseudoRandomBytes(16, function (err, raw) {
cb(null, raw.toString('hex') + Date.now() + '.' + mime.getExtension(file.mimetype));
});
}
});
let upload = multer({
limits: {
fileSize: 1000000
},
fileFilter: function(req, file, cb) {
if(!file.originalname.match(/\.(jpg|jpeg|png)$/)){
return cb('File must be an image.');
}
cb(undefined, true);
},
storage: storage
});
Route:
app.post('/upload-ad', upload.any(), recaptcha.middleware.verify, (req, res)
If I test your code like below, I get the correct response, e.g. "File must be an image." if I try to upload a .gif file.
const request = require("request");
const fs = require("fs");
const options = {
method: "POST",
url: "http://localhost:3300/upload-ad",
headers: {
"Content-Type": "multipart/form-data"
},
formData : {
"image" : fs.createReadStream("./test.gif")
}
};
request(options, function (err, res, body) {
if(err) console.log(err);
console.log(body);
});
This works because we're setting the Content-Disposition field in this case. I suspect that what's happening to you is that maybe the client is not setting this header, or it was set incorrectly. For example if we changed a filename from "test.gif" to "test.jpg" this would upload successfully despite the fact it is actually a GIF image.
In my case the start of the upload looks like so:
----------------------------321622124424983663382061
Content-Disposition: form-data; name="image"; filename="test.gif"
Content-Type: image/gif
And everything works as it is supposed to.
I'd recommend maybe not trusting the filename field in the POST and actually check what the image really is by looking at the uploaded buffer.
I have two apis, I want to send a file from the first api using request and formData.
How to receive req.file from request form-data ?
Receive side code
var storage = multer.diskStorage({
destination: function (req, file, cb) {
mkdirp(configServer.dataDir+ "/tmp", function(err){
cb(null, configServer.dataDir+ "/tmp/")
})
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
var upload = multer({ storage: storage }).single('file');
exports.upload_in_server = function (req, res) {
upload(req, res, function (err) {
console.log("file : ", req.file)
console.log("body : ", req.body)
res.json({success: true})
})
}
router.post("/myurl/uploadInServer", UserController.upload_in_server);
Send side code
var storage2 = multer.diskStorage({
destination: function (req, file, cb) {
mkdirp(config.dataDir+ "/tmp", function(err){
cb(null, config.dataDir+ "/tmp/")
})
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
var upload2 = multer({ storage: storage2 }).single('file');
exports.user_coffre_fort_create_file2 = function (req, res) {
upload2(req, res, function (err) {
var obj = {
'Nom': "Lagaf",
'Prénom': "Vincent",
'Date de naissance': "13/01/1960",
'file':new Buffer(fs.readFileSync(req.file.path)).toString("base64")
}
request({
url: "/myurl/uploadInServer",
method: 'POST',
formData: obj,
headers: {"Content-Type": "application/x-www-form-urlencoded", "Authorization": token}
}, function (err, stdout, body) {
res.json({success:true})
})
})
}
This is what I receive
the req.file is null, and i received the file in the body
How to recevie the file in the req.file ?
Thanks in advance
file : undefined
body : {
'Nom: 'Lagaf',
'Prénom': 'Vincent',
'Date de naissance': '13/01/1960',
file:/9j/4gIcSUNDX1BST0ZJTEUAAQEAAAIMbGNtcwIQAABtbnRyUkdCIFhZWiAH3AABABkAA
You need to use multipart/form-data as content type for uploading files and form feature from requests module. Take a look at this answer.
My current implementation is as follows:
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'public/images/items/')
},filename: function (req, file, cb) {
let ext = '';
if (file.originalname.split(".").length>1)
ext = file.originalname.substring(file.originalname.lastIndexOf('.'), file.originalname.length);
cb(null, Date.now() + ext)
}
})
...Using route....
app.post('/updateItemImage', upload.single('image'), function (req, res, next) {
console.log('user: ' + req.user.id + ' updating image: ' + req.body.item_id);
})
..Alright. That works. req.body.item_id is present in my route, and multer handles req.file, saving it to disk with a unique filename.
however...
I'd like the item to be saved using multer, only if req.user.id and req.body.item_id have certain values. req.body.item_id is undefined within the scope of:
filename: function (req, file, cb) {
So I can't move my code into this function.
TLDR: post function needs to capture req.body.item_id, and req.file. If req.body.item_id == value than save file and res.send('ok') There's more than one way to skin a cat. What's an option that would work?
EDIT: here is the frontend js:
$scope.uploadFile = function(files) {
var fd = new FormData();
var uploadUrl = '/updateItemImage';
var fd = new FormData();
fd.append("image", files[0]);
fd.append("item_id", '11');
$http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
}).then(function (response) {
if (response.data == 'ok') {
return
}
alert('something went wrong')
})
}
EDIT: Swapping the order of parameters so that the body param was first:
fd.append("item_id", '11');
fd.append("image", files[0]);
Resolved my issue. This shouldn't matter!
req.body.item_id is undefined within the scope of:
filename: function (req, file, cb) {
I've already tested it, it worked, the value is not undefined in that scope
Don't upload photos to the server, how to solve this problem?
on the page index.ejs a photo gallery should be generated from the added entries. The entry contains a photo. The entry is added, but the photo doesn't load.
project (GitHub)
app/routes.js:
var upload = multer({
storage: storage,
limits: {fileSize: 7},
fileFilter: function (req, file, cd) {
checkFileType(file, cd);
}
}).single('filePhoto');
function checkFiletType(file, cd) {
const fileTypes = /jpeg|jpg/;
const extname = fileTypes.test(path.extname(file.originalname).toLowerCase());
const mimetype = fileTypes.test(file.mimetype);
if (extname && mimetype) {
return cd(null, true);
} else {
cd('Error: only JPEG or JPG!')
}
var Photo = require('../app/models/photo');
module.exports = function (app, passport) {
app.get('/', function (req, res,next) {
Photo.find({}, function (error, photos) {
var photoList = '';
res.render('index.ejs', {photoList: photos});
});
});
}
app.post('/addPhoto', function (req, res, next) {
next();
}, function (req, res) {
var newPhoto = new Photo(req.body);
newPhoto.save().then(function (response) {
console.log('here', response);
res.status(200).json({code: 200, message: 'OK'});
}).catch(function (error) {
console.error('new photo error', error);
});
},function (req, res) {
Photo.find({}, function (error, photos) {
res.send('index.ejs', {
photoList: photos
});
});
});
};
You need to pass your upload var as middleware to your upload route.
Here is a snippet from how I have done it previously:
// Route:
const storage = multer.memoryStorage()
const upload = multer({ storage: storage })
router.post('/upload', upload.single('photo'), ImageController.upload);
// Image Controller:
upload(req, res){
console.log("file", req.file)
}
When I post my image, I make sure I call it photo to match the key word I used in my multer middleware:
So I create my form data like so:
const formData = new FormData()
formData.append('photo', {
uri: data.uri,
type: 'image/jpeg',
});
axios.post(`${SERVER}/images/upload`,
formData: formData,
{ headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(response => console.log("response", response))
.catch(err => console.log('err', err))