I have been debugging this all day and am finally out of googling options.
I have a Vue3 frontend that receives an image and is supposed to send said image to the backend. I have verified that the image is, in fact, being sent, but the file object in Multer is showing undefined every time regardless of what the front-end / network says is being sent.
Here's my code
Frontend
<template>
<div >
<div >
<label for="formFile"
>Upload a new profile picture</label
>
<input
type="file"
@change="onSelect"
id="formFile"
/>
<span > {{ message }} </span>
</div>
</div>
</template>
<script>
import axios from "redaxios";
export default {
name: "FileUpload",
props: {
user: Array | Object,
},
created() {},
data() {
return {
file: "",
message: "",
};
},
methods: {
onSelect(e) {
this.file = e.target.files[0] || e.dataTransfer.files;
if (this.file.length) return;
const formData = new FormData();
console.log(this.file);
formData.append("id", this.user.id);
formData.append("file", this.file);
//formData.set("enctype", "multipart/form-data");
console.log(formData);
try {
axios
.post("http://localhost:3669/uploadPhoto", formData)
.then((res) => {
this.message = "Uploaded successfully!";
});
} catch (err) {
console.log(err);
this.message = "Something went wrong uploading your photo!";
}
},
},
};
</script>
Backend
const fileFilter = (req: express.Request, file: File, cb) => {
const allowedTypes = /jpeg|jpg|png|gif/;
const extname = allowedTypes.test(path.extname(file.name).toLowerCase());
const mimetype = allowedTypes.test(file.type);
if (!mimetype && extname) {
const error = new Error("Incorrect Filetype");
error.name = "INCORRECT_FILETYPE";
return cb(error, false);
}
cb(null, true);
}
const storage = multer.diskStorage({
destination: function (req, file, cb) {
if (req.body.id) {
cb(null, `./public/photos/${req.body.id}`)
} else {
cb(null, "./public/photos");
}
},
filename: function (req, file: File, cb) {
console.log(req.file);
cb(null, file.name ".png");
},
});
const imageUpload : Multer = multer({
storage,
limits: {
fileSize: 5000000
}
});
app.post('/uploadPhoto', imageUpload.single('file'), async (req: express.Request, res:express.Response) => {
console.log(req.body);
console.log(req.file);
res.json({ message: 'Successfully uploaded file' });
return;
});
I omitted some code for space reasons, but for some reason it just won't work. Logged file returns a file, but the backend refuses to see it.
Thanks
- Zach
CodePudding user response:
It seems your Multer DiskStorage configuration is the cause of the problems.
My guess is you have the wrong file paths because ./
is not what you think. This is why it's always good to resolve paths from __dirname
(the current script's parent directory).
You also have the wrong argument type in your filename
hook. The file
argument is of type Expres.Multer.File
. You don't need to set this as it's already defined by the function signature.
import { resolve } from "path";
import multer from "multer";
const uploadBase = resolve(__dirname, "public", "photos");
const storage = multer.diskStorage({
destination: (req, _file, cb) => {
cb(null, req.body.id ? resolve(uploadBase, req.body.id) : uploadBase);
},
filename: (_req, file, cb) => {
cb(null, file.originalname); // note the property used
}
});
Make sure you install @types/multer
as a dev-dependency to get useful linting in your editor.