I am trying to upload image file via multer and I dont understand why req.file returns undefined
I have set up form encType to mulipart/form-data, input name matches with the upload.single() parameter. I have also tried to set header multipart/form-data via axios but also did not help
auth.js
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, DIR);
},
filename: (req, file, cb) => {
const fileName = file.originalname.toLowerCase().split(" ").join("-");
cb(null, Date.now() + "-" + fileName);
},
});
const upload = multer({
storage: storage,
fileFilter: (req, file, cb) => {
if (
file.mimetype == "image/png" ||
file.mimetype == "image/jpg" ||
file.mimetype == "image/jpeg"
) {
cb(null, true);
} else {
cb(null, false);
return cb(new Error("Only .png, .jpg and .jpeg format allowed!"));
}
},
});
router.post(
"/changeAvatar",
upload.single("avatar"),
userAuth,
async (req, res, next) => {
try {
console.log(req.file);
const url =
req.protocol + "://" + req.get("host") + "/public/" + req.file.filename;
const user = await User.findByIdAndUpdate(req.user.id, { image: url });
res.json({ user });
} catch (err) {
res.json({ err });
}
}
);
react form
<form
onSubmit={handlePostAvatar}
encType="multipart/form-data"
>
<input
// style={{ display: "none" }}
type="file"
name="avatar"
id="avatar"
// ref={avatarFileRef}
onChange={changeHandle}
/>
<button style={{ cursor: "pointer" }}>Save</button>
</form>
post request
const handlePostAvatar = async (e) => {
e.preventDefault();
try {
const res = await axios.post("/api/auth/changeAvatar");
console.log(res);
} catch (err) {
console.log(err);
}
};
Related
I'm trying to adapt my code to upload files, but I'm not getting it, I looked in the community and I didn't understand, I'm still new to this. It always falls on the error json return, do you know what it can be?
File where you have the logic
async img(request, response){
multer({
storage: multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "./Uploads")
},
filename: (req, file, cb) => {
cb(null, Date.now().toString() + '-' + file.originalname)
},
fileFilter: (req, file, cb) => {
const extensionImg = ['image/png', 'image/jpg', 'image/jpeg'].find
(formatPermitted => formatPermitted == file.mimetype)
if(extensionImg){
return cb(null, true)
}
return cb(null, false)
}
})
}).single('image')
if(request.file){
return response.status(200).json({erro: false, message: "ok"});
}else{
return response.status(400).json({erro: true, message: "error"});
}
}
File where the route is
const IncidentsController = require('./controllers/IncidentsController');
const routes = express.Router();
routes.post('/uploads', IncidentsController.img)
multer(...).single(...) returns a middleware function. That middleware function that it returns has to be actually called in order to do something.
Typically, you would define the middleware outside a request handler and then use it as middleware on one or more request handlers.
const imgMulterMiddleware = multer({
storage: multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "./Uploads")
},
filename: (req, file, cb) => {
cb(null, Date.now().toString() + '-' + file.originalname)
},
fileFilter: (req, file, cb) => {
const extensionImg = ['image/png', 'image/jpg', 'image/jpeg'].find
(formatPermitted => formatPermitted == file.mimetype)
if(extensionImg){
return cb(null, true)
}
return cb(null, false)
}
})
}).single('image');
Then, use that middleware as needed:
routes.post('/uploads', imgMulterMiddleware, (req, res) => {
// do something with req.file here which will be set
// by the middleware if it was successful
if (req.file) {
res.json({erro: false, message: "ok"});
} else {
res.status(400).json({erro: true, message: "error"});
}
});
This is my storage for multer I want to name files with session username and that is where my problem lays
If I const upload outside I cannot access req.session.user.username anymore...
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "./uploads/usersprofile/");
},
filename: function (req, file, cb) {
cb(
null,
file.fieldname +
"_" +
`${req.session.user.username}${path.extname(file.originalname)}`
);
},
});
This is my route to which I upload file but it uploads file but gives me "upload is not a function" error I am unsure how to make it work with if (req.session.user && req.session.user.username) {} and so it doesn't allow not logged in users to upload plus not show "upload is not a function" error
router.post(
"/uploadpicture",
multer({
storage: storage,
fileFilter: (req, file, cb) => {
if (
file.mimetype == "image/png" ||
file.mimetype == "image/jpg" ||
file.mimetype == "image/jpeg"
) {
cb(null, true);
} else {
cb(null, false);
return cb(new Error("Only .png, .jpg and .jpeg format allowed!"));
}
},
limits: { fileSize: maxSize },
}).single("avatar"),
(req, res) => {
if (req.session.user && req.session.user.username) {
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
res.send(err);
} else if (err) {
res.send(err);
}
});
} else {
res.json({ loggedIn: false });
}
}
);
Fixed by creating const upload that leads to "avatar" const upload = myMulter.single("avatar");
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "./uploads/usersprofile/");
},
filename: function (req, file, cb) {
cb(
null,
file.fieldname +
"_" +
`${req.session.user.username}${path.extname(file.originalname)}`
);
},
});
const myMulter = multer({
storage: storage,
fileFilter: (req, file, cb) => {
if (
file.mimetype == "image/png" ||
file.mimetype == "image/jpg" ||
file.mimetype == "image/jpeg"
) {
cb(null, true);
} else {
return cb(new Error("Only .png, .jpg and .jpeg format allowed!"));
}
},
limits: { fileSize: maxSize },
});
const upload = myMulter.single("avatar");
router.post("/uploadpicture", (req, res) => {
if (req.session.user && req.session.user.username) {
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
res.send(err);
} else if (err) {
res.send(err);
}
});
} else {
res.json({ loggedIn: false });
}
});
I have a problem with express.js and multer when I try to upload 2 valid images and 1 example pdf to validate is all images, it will upload that two images into a folder, and then it will throw the error for pdf that is an invalid format, can I somehow validate first all images and then do the upload to folder or throw the error is something is wrong here is my code
const fileStorageEngine = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, './images');
},
filename: (req, file, cb) => {
cb(null, Date.now()+ '--' +file.originalname);
}
});
const fileFilter = (req, file, cb) => {
// Reject a file
if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/jpg' || file.mimetype === 'image/png') {
cb(null, true);
} else {
req.fileValidationError = 'File type not supported';
cb(null, false);
}
};
const upload = multer({
storage: fileStorageEngine,
limits: {
fileSize: 1024 * 1024 * 5 // Accept files to 5mb only
},
fileFilter: fileFilter
});
app.post('/multiple', upload.array('images', 3), async(req, res, next) => {
try {
console.log("POST Multiple Files: ", req.files);
if (await req.fileValidationError) {
throw new Error(req.fileValidationError);
} else {
for (let i = 0; i < req.files.length; i++) {
let storeImage = await StoreImages.create({
images: req.files[i].path
});
if (!storeImage) {
throw new Error('Sorry, something went wrong while trying to upload the image!');
}
}
res.status = 200;
res.render("index", {
success: true,
message: "Your images successfully stored!"
});
}
} catch(err) {
console.log("POST Multiple Error: ", err);
res.status = 406;
return res.render('index', {
error: true,
message: err.message
})
}
});
I want to validate all uploaded files before insert to a folder, server, etc...
I found a solution by throwing the error in cb function in fileFilter function
const fileFilter = (req, file, cb) => {
// Reject a file
if(file.mimetype === 'image/jpeg' || file.mimetype === 'image/jpg' || file.mimetype === 'image/png'){
cb(null, true);
}else{
cb(new Error('File type not supported'));
}
};
I am using Multer to save images but I need to get the path of the image to save it to MongoDB. I am trying to get the path with req.file but it always tells me on the console that it is undefined.
this is my route:
import { Router } from 'express';
import { check, validationResult } from 'express-validator';
const multer = require('multer');
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/products')
},
filename: function (req, file, cb) {
cb(null, new Date().toISOString().replace(/:/g, '-') + file.originalname)
}
});
const fileFilter = (req, file, cb) => {
// reject a file
if (file.mimetype === 'image/jpeg' ||file.mimetype === 'image/png') {
cb(null, true);
} else {
cb(null, false);
//cb(new Error('I don\'t have a clue!'))
}
}
const upload = multer(
{ storage: storage,
limits:{
fileSize: 1024 * 1024
},
fileFilter: fileFilter
});
let router = Router();
router.post('/', upload.single('img'),
newProduct
);
And in the new Product controller I am trying to read the req.file but the console tells me that it is undefined:
Controller:
import { Product } from '../models'
let newProduct = async (req, res = response ) => {
console.log('file ' + req.file); //UNDEFINED
try {
let { status, user, ...body } = req.body;
let productDB = await Product.findOne ( { 'name': body.name } );
if (productDB) {
return res.status(400).json({
msg:`El producto ${ productDB.name } ya existe`
})
}
let data = {
...body,
name: body.name,
user: req.user._id
}
let product = new Product( data );
await product.save();
res.status(200).json( product );
} catch (error) {
return res.status(400).json({
error
});
}
}
Console:
Thanks for your help.
you can try to do this in filename instead:
filename: function (req, file, cb) {
req.imageName = new Date().toISOString().replace(/:/g, '-') + file.originalname
cb(null, req.imageName)
}
then there:
console.log('file ' + req.file); //UNDEFINED
//you can get imageName instead
console.log('imageName',req.imageName)
//if you want url to store in database you can do this
//supposing your have images directory in root of your node server
const url = `${req.protocol}://${req.get('host')}/images/${req.body.image}`
I'm trying to upload a picture where the user registers in the app. When I'm trying to test it in insomnia I get the following error: MulterError: Unexpected field at wrappedFileFilter
I've been reading online and I know this error occurs when there is a mismatch between the field name provided by the client and the field name expected by the server. However, I've been checking many times my code and the name that I give in the server and the client (Insomnia) is the same: "image". Any idea what else can I try?
Here is my code:
const storage = multer.diskStorage({
destination: './client/public/img',
filename: (req, file, cb) => {
console.log(file)
cb(null, file.originalname)
}
})
const fileFilter = (req, file, cb) => {
if(file.mimetype == "image/jpeg" || file.mimetype == "image/png") {
cb(null, true)
} else {
cb(null, false)
}
}
const upload = multer({ storage: storage, fileFilter: fileFilter, destination: './client/public/img' })
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
//sign up
routes.post("/register", upload.single("image"), (req, res) => {
let { user_name, email, password, password2 } = req.body;
let { image } = req.file.filename
let errors = []
//check required inputs
if(!user_name || !email || !password || !password2){
errors.push({message: "Please fill all required fields"})
res.send({message: "Please fill all required fields"})
}
//check passwords
if(password != password2) {
errors.push({message: "Passwords do not match"})
res.send({message: "Passwords do not match"})
}
if(errors.length>0) {
console.log(errors);
} else {
if(email) {
db(`SELECT * FROM user WHERE email = "${email}"`)
.then((results) => {
if(results.data.length>0){
res.send("Email exists")
} else {
bcrypt.hash(password, saltRounds, (err, hash) => {
password = hash
db(`INSERT INTO user (user_name, email, password, image) VALUES ("${user_name}", "${email}", "${password}", "${image}")`)
.then((results) => {
res.send("Registration successful")
if(err)throw err;
})
.catch((error) => {
console.log(error)
})
})
}
})
.catch((error) => {
console.log(error)
})
} else {
res.send("Enter email")
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Any help will be appreciated. Thanks in advance.
I am making the assumption that you are using form to upload your file. If, so...
Front end snippet:
<form action="/register" method="post" enctype="multipart/form-data">
<input type="file" name="image" />
</form>
Get multer to upload the file correctly:
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './client/public/img')
},
filename: function (req, file, cb) {
if(file.mimetype == "image/jpeg" || file.mimetype == "image/png") {
cb(null, file.fieldname + '-' + Date.now());
}
else {
cb(new MulterError('LIMIT_UNEXPECTED_FILE', file.fieldname));
}
});
const upload = multer({ storage: storage });
Handle the error inside your Express middleware by calling upload as below...
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.
})
})