Home > Software engineering >  Vue Frontend - Multer Express - Req.File is undefined
Vue Frontend - Multer Express - Req.File is undefined

Time:04-01

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.

  • Related