I am giving post request /product/create with some value and an image.
if I console every value before
upload(req, res, (err) => {})
it is showing properly with out image info.
if I receive the value after upload(req, res, (err) => {})
No value is showing.
Full post request code:
app.post('/product/create', (req, res) => {
let filename;
upload(req, res, (err) => {
if(err){
res.render('index', {
msg: err
});
} else {
if(req.file == undefined){
res.render('index', {
msg: 'Error: No File Selected!'
});
} else {
res.render('index', {
msg: 'File Uploaded!',
filename = req.file.filename;
});
}
}
});
const product = {
title : req.body.title,
desc : req.body.desc,
image : filename,
}
});
configuring Multer:
const storage = multer.diskStorage({
destination: './public/uploads/',
filename: function(req, file, cb){
cb(null,file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
const upload = multer({
storage: storage,
limits:{fileSize: 1000000},
fileFilter: function(req, file, cb){
checkFileType(file, cb);
}
}).single('myImage');
function checkFileType(file, cb){
const filetypes = /jpeg|jpg|png|gif/;
const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
const mimetype = filetypes.test(file.mimetype);
if(mimetype && extname){
return cb(null,true);
} else {
cb('Error: Images Only!');
}
}
Multer does not support 'req.file.filename' outside upload function. As filename, originalname, fieldname etc is inbuild API of multer. It is limited to upload function only.
Now, if you are trying to upload product values inside database then you have to create an insert function inside multer upload function only.
Related
I am trying to upload an image from my front end to the backend but it it doesn't send the image in the request
It says that the formdata is empty and it says that there's no image found, where is the problem and how can I fix this error?
Here is the code from the Frontend made in react:
const [userInfo, setuserInfo] = useState({
file:[],
filepreview:null,
});
const handleInputChange = (event) => {
setuserInfo({
...userInfo,
file:event.target.files[0],
filepreview:URL.createObjectURL(event.target.files[0]),
});
}
const [isSucces, setSuccess] = useState(null);
const submit = async () =>{
const formdata = new FormData();
formdata.append('avatar', userInfo.file);
console.log(formdata)
Axios.post("http://localhost:4000/imageupload", formdata,{
headers: { "Content-Type": "multipart/form-data" }
})
.then(res => { // then print response status
console.warn(res);
if(res.data.success === 1){
setSuccess("Image upload successfully");
}
})
}
The code of the Backend made in NodeJS:
const storage = multer.diskStorage({
destination: path.join(__dirname, './temp', 'uploads'),
filename: function (req, file, cb) {
// null as first argument means no error
cb(null, Date.now() + '-' + file.originalname )
}
})
app.post('/imageupload', async (req, res) => {
try {
// 'avatar' is the name of our file input field in the HTML form
let upload = multer({ storage: storage}).single('avatar');
upload(req, res, function(err) {
// req.file contains information of uploaded file
// req.body contains information of text fields
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);
}
const classifiedsadd = {
image: req.file.filename
};
res.send("ok")
});
}catch (err) {console.log(err)}
})
Edit:
Multer is essentially a nodejs router,i.e. a function that can be pipelined between your HTTP request and HTTP response.
I think that you should first make multer analyze your HTTP content and to actually populate the req.file before actually evaluate express parsers do their job.
const storage = multer.diskStorage({
destination: path.join(__dirname, './temp', 'uploads'),
filename: function (req, file, cb) {
// null as first argument means no error
cb(null, Date.now() + '-' + file.originalname )
}
})
let upload = multer({ storage: storage});
app.post('/imageupload', upload.single('avatar'), async (req, res) => {
try {
// 'avatar' is the name of our file input field in the HTML form
// req.file contains information of uploaded file
// req.body contains information of text fields
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);
}
const classifiedsadd = {
image: req.file.filename
};
res.send("ok")
}catch (err) {console.log(err)}
})
I am assuming that your upload code is working. Have you tried to read the HTTP request from your browser to see that the image has been correctly attached to the request?
Because probably the issue lies in the fact that you are not actually parsing the image.
const file = new File(userInfo.file, "avatar.png", {
type: 'image/png' // choose the appropriate
});
const formdata = new FormData();
formdata.append('avatar', file);
console.log(formdata)
I want to upload files from the form data in react which is being posted by axios like this.
const addNewProduct = () => {
const newProduct = {
name: name,
cost: cost,
size: size,
color: color,
material: material,
discount: discount,
description: description,
category: category
};
const nulls = Object.values(newProduct).filter(p => p === null);
if(nulls.length === 0 && images.imageFiles) {
let productFormData = new FormData();
productFormData.append('productInfo', JSON.stringify(newProduct));
productFormData.append('productImages', images.imageFiles);
const addUrl = "http://localhost:8080/cpnl/addproduct";
axios({
method: "POST",
url: addUrl,
data: productFormData,
headers: { "Content-Type": "multipart/form-data" }
})
.then((response) => {
console.log(response.data.msg);
})
.catch((response) => {
console.error(response);
});
}else {
Notiflix.Notify.Warning("Check your inputs!");
console.log(nulls);
console.log("product: \n" + JSON.stringify(newProduct));
}
};
then I want to upload images with multer to images folder. this is my code:
const storage = multer.diskStorage({
destination: "./public/images",
filename: (req, file, cb) => {
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
const upload = multer({
storage: storage,
limits:{fileSize: 1000000},
fileFilter: function(req, file, cb){
checkFileType(file, cb);
}
}).array("productImages", 5);
function checkFileType(file, cb) {
// Allowed ext
const filetypes = /jpeg|jpg|png/;
// Check ext
const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
// Check mime
const mimetype = filetypes.test(file.mimetype);
if(mimetype && extname){
return cb(null,true);
} else {
cb('Error: Images Only!');
}
}
//receive form data from front-end and add new product to database
router.post('/addproduct', async (req, res) => {
upload(req, res, (err) => {
if(err) {
res.status(400).json({
msg: err
});
} else {
if(req.files == undefined) {
res.status(400).json({
msg: "Error: No file selected! please contact the developer."
});
} else {
data = req.body.productInfo;
res.status(200).json({
msg: "Files uploaded!"
});
console.log( "images: " + req.files);
console.log("data" + data);
}
}
});
});
first problem: I'm getting image files inside req.body.productImages and not inside req.files
second problem: when I send the request node js throws me this error:
TypeError: upload is not a function
why everything is messed up!?
Edit: I restarted the server and now I'm getting data but the files are not being uploaded. no error is shown.
UPDATE: second problem fixed
First Problem : You have used .array("productImages", 5); in your upload function. use .array("files", 5); to get the file in req.files.
Second Problem : I guess there is some typo error in your code upload(req, res, (err)... there is one extra bracket it should be only upload(req,res,err )...
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
});
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))
I'm trying to upload multipart form data using multer. I'm using swagger express middleware for my APIs. Without swagger everything was working. But with swagger, file is not uploaded. There's no validation error, but it simply doesn't upload file. Here's some code that you may want to see:
app.js
SwaggerExpress.create(config, function(err, swaggerExpress) {
if (err) { throw err; }
swaggerExpress.register(app);
var port = 8850;
https.createServer(options, app).listen(port, function () {
console.log('Bus993 server started # %s!', port);
});
});
upload function
function uploadImage(req, res, multer){
console.log("here", req.files);
//ABOVE SHOWS A VALID FILE
var storage = multer.diskStorage({
destination: function (req, file, cb) {
console.log("fILE", file);
//THIS IS NOT PRINTED
cb(null, '../../public/images');
},
filename: function (req, file, cb) {
console.log(file);
//THIS IS NOT PRINTED
cb(null, file.originalname.replace(/[.]{1}[a-zA-Z]+$/, "") + '_' + moment().format('X') + getExtension(file));
}
});
var upload = multer({storage: storage, fileFilter: fileFilter}).single('imageFile');
upload(req, res, function (err) {
if (err) {
res.status(422).json(
{
status: "error",
data: {error: err.message},
message: "Image upload failed."
}
);
} else {
res.status(200).json(
{
status: "success",
data: "",
message: "Image uploaded successfully."
}
);
}
});
function fileFilter(req, file, cb) {
console.log("fILE", file);
if ((file.mimetype != 'image/jpeg' && file.mimetype != 'image/png' && file.mimetype != 'image/gif') || file.size > 8000) {
cb(new Error('Invalid file.'), false);
} else {
cb(null, true);
}
}
function getExtension(file) {
var res = '';
if (file.mimetype === 'image/jpeg') res = '.jpg';
if (file.mimetype === 'image/png') res = '.png';
if (file.mimetype === 'image/gif') res = '.gif';
return res;
}
}
So, the problem seems that file is undefined here since when I'm using swagger. Earlier it was fine. But now it returns status:success but image was never uploaded.
Am I doing something wrong?
swaggerExpress uploading a file local/s3 successful
following setups are:
1. in swagger file(yaml)
/s3/upload:
x-swagger-router-controller: s3/upload
post:
operationId: upload
tags:
- S3
consumes:
- multipart/form-data
parameters:
- in: formData
name: file
description: The file to upload
type: file
2.add extra middleware
SwaggerExpress.create(config, function(err, swaggerExpress) {
if (err) { throw err; }
// install middleware
app.use(SwaggerUi(swaggerExpress.runner.swagger));
// install extra middleware
app.use(function (req, res, next) {
if(req.file){
req.files = req.file
}else{
req.files = {}
}
next();
});
// install middleware
swaggerExpress.register(app);
console.log("Listening on port: "+ port)
app.listen(port);
});
3.controller using multer,multerS3 and aws-sdk
define middleware before controller
s3 object
const uploadFile = multer({
storage: multerS3({
s3: s3,
bucket: 'bucket_name',
metadata: function (req, file, cb) {
cb(null, {fieldName: file.fieldname});
},
key: function (req, file, cb) {
cb(null, file.originalname)
}
})
}).fields([{name: "file"}])
controller.upload = async function(req, res, next){
console.log("---------upload---------------");
try{
uploadFile(req, res, function (error) {
if (error) {
console.log(error);
res.json({
result: "Error",
status: false
})
}else{
console.log('File uploaded successfully.',req.files);
res.json({
result: req.files.file[0],
status: true
})
}
});
}catch(e){
res.json({
message: "Error"
})
}
}
enter image description here