Home > Enterprise >  req.file is undefined (react.js and multer)
req.file is undefined (react.js and multer)

Time:04-02

I am trying to upload a file but I can't do it. I got a name for my file in database but I don't have the file in my file folder. When I am doing a console.log(req.file), I got an "undefined" I don't know what I'm missing I am using node.js, mySql (sequelize). React in front

app.js

const express = require('express');
const cookieParser = require('cookie-parser')
const app = express();
const path = require('path');

const userRoutes = require('./routes/user')
const postRoutes = require('./routes/post')
const commentRoutes = require('./routes/comment')

// no cors error
app.use((req, res, next) => {
  const allowedOrigins = ['http://127.0.0.1:3000', 'http://localhost:3001', 'http://127.0.0.1:4200', 'http://localhost:4200'];
  const origin = req.headers.origin;
  if (allowedOrigins.includes(origin)) {
       res.setHeader('Access-Control-Allow-Origin', origin);
  }
  //res.header('Access-Control-Allow-Origin', 'http://127.0.0.1:8020');
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  res.header('Access-Control-Allow-Credentials', true);
  return next();
});

// request access req.body
app.use(express.json());
app.use(cookieParser())

app.use('/images', express.static(path.join(__dirname, 'images')));
// app.use('/front/public/uploads/posts', express.static(path.join(__dirname, 'front/public/uploads/posts')));

// routes
app.use('/api/auth', userRoutes)
app.use('/api/post', postRoutes)
app.use('/api/comment', commentRoutes)

module.exports = app;

ROUTES 

const express = require('express');
const router = express.Router();

const postCtrl = require('../controllers/post');
const auth = require('../middleware/auth')
const multer = require('../middleware/multer-config');

router.get('/', postCtrl.getAllPost);
router.post('/', auth, multer, postCtrl.createPost);

module.exports = router;

middleware/multer.js

const multer = require('multer');

// MIME types dictionnary
const MIME_TYPES = {
  'image/jpg': 'jpg',
  'image/jpeg': 'jpg',
  'image/png': 'png'
};

const storage = multer.diskStorage({
  destination: (req, file, callback) => {
    callback(null, 'images');
  },
  filename: (req, file, callback) => {
    const name = file.originalname.split(' ').join('_');
    const extension = MIME_TYPES[file.mimetype];
    callback(null, name   Date.now()   '.'   extension);
  }
});

module.exports = multer({storage: storage}).single('image');

Post.js

const models = require('../models');
const jwt = require('jsonwebtoken');

// create a post
exports.createPost = async(req, res, next) => {
    const token = req.cookies.jwt;
    const decodedToken = jwt.verify(token, process.env.JWT_TOKEN);
    const userId = decodedToken.userId;

    console.log(req.file) // undefined
    models.User.findOne({ where: { id: userId } })
    .then((userFound) => {
        if (userFound) {
            if (req.file) {
                const post = new models.Post({
                    UserId: userFound.id,
                    content: req.body.content,
                    imageUrl: `${req.protocol}://${req.get('host')}/images/${req.file.filename}`,
                })
                console.log(post)
                post.save()
                .then(() => res.status(201).json({ message: 'Post avec image créé !' }))
                .catch(error => res.status(400).json({ error: 'Le post avec image n\'a pas pu être créé !' }));
            }
            else {
                const post = new models.Post({
                    UserId: userFound.id,
                    content: req.body.content,
                    imageUrl: req.body.imageUrl,
                })
                console.log('post sans image')
                console.log(post)
                post.save()
                .then(() => res.status(201).json({ message: 'Post sans image créé !' }))
                .catch(error => res.status(400).json({ error }));
            }
        }
        else {
            return res.status(404).json({ error: 'Utilisateur non trouvé' })
        }
    })
};

front part (using react) postForm.js

import axios from 'axios';
import React, { useContext, useEffect, useState } from 'react';
import { NavLink } from 'react-router-dom';
import { UserContext } from '../../UserContext';
import { isEmpty } from './../Utils'

const NewPostForm = () => {
    const uid =  useContext(UserContext)
    const [firstName, setFirstName] = useState('')
    const [lastName, setLastName] = useState('')

    const [message, setMessage] = useState('')
    const [postPicture, setPostPicture] = useState('')
    const [video, setVideo] = useState('')
    const [file, setFile] = useState('')

    useEffect(() => {
        const getUserInfo = async () => {
            if (uid !== null) {
                const userId = uid.userId
                await axios ({
                    method: "get",
                    url: `http://localhost:3000/api/auth/${userId}`,
                    withCredentials: true,
                })
                .then((res) => {
                    setFirstName(res.data.first_name)
                    setLastName(res.data.last_name)
                })
                .catch((err) => {
                    console.log(err)
                })
            }
        }
        getUserInfo()

    }, [uid, firstName, lastName])

    const handlePost = async () => {
        if (message || postPicture || video) {
            const data = new FormData()
            // data.append("video", video)
            data.append("UserId", uid.userId)
            data.append("content", message)
            if (file) data.append("imageUrl", file.name)

            console.log(file)

            axios({
                method: "post",
                baseURL: `http://localhost:3000/api/post`,
                withCredentials: true,
                headers: {
                    'Content-Type': 'application/json'
                },
                data: data
            })
            .then((res) => {
                console.log(res.data)
            })
            .catch((err) => {
                console.log(err)
            })
            // cancelPost()
        } else {
            alert("Veuillez entrer un message")
        }
    }

    const handlePicture = (e) => {
        setPostPicture(URL.createObjectURL(e.target.files[0]))
        setFile(e.target.files[0])
        // setVideo('')
    }

    const cancelPost = () => {
        setMessage('')
        setPostPicture('')
        setVideo('')
        setFile('')
    }

    return (
        <div className='post-container' style={{border: "1px solid black"}}>
            <NavLink to="/profile">
                <div className='user-info'>
                    <img src="uploads/profile.jpg" width="50px" alt="profil de l'utilisateur" />
                    <p>{firstName} {lastName} is connected</p>
                </div>
            </NavLink>
            <div className='post-form'>
                <textarea
                    type="text"
                    name="message"
                    id="message"
                    cols="50"
                    rows="5"
                    placeholder='Quoi de neuf ?'
                    onChange={(e) => setMessage(e.target.value)}
                    value={message}
                ></textarea>
                <img src={postPicture} alt="" className="img-preview" width="200px" />
            </div>

            <div className='footer-form'>
                <div className='icon'>
                    {isEmpty(video) && (
                        <>
                        <img src="" alt="icone paysage" />
                        <input
                            type="file"
                            id='file-upload'
                            name='file'
                            accept='.jpg, .jpeg, .png'
                            onChange={(e) => handlePicture(e)}
                        />
                        </>
                    )}
                    {video && (
                        <button onClick={(e) => setVideo('')}>Supprimer vidéo</button>
                    )}
                </div>
                <div className='btn-send'>
                    {message || postPicture || video.length > 20 ? (
                        <button className='cancel' onClick={(e) => cancelPost()}>Annuler</button>
                    ) : null}
                    <button className='send' onClick={(e) => handlePost()}>Envoyer</button>
                </div>
            </div>
        </div>
    );
};

export default NewPostForm;

CodePudding user response:

You need to send the actual file rather than just the name of the file. The server will not be able to access the file from a user's computer by its name.

To send a file in a post request, you also need to change the content type of the request to one that Multer expects.

const handlePost = async () => {
    if (message || postPicture || video) {
        const data = new FormData();
        data.append("UserId", uid.userId);
        data.append("content", message);
        if (file) {
            data.append("image", file);
        }

        try {
            const res = await axios({
                method: "post",
                baseURL: `http://localhost:3000/api/post`,
                withCredentials: true,
                headers: { 'Content-Type': 'multipart/form-data' },
                data: data,
            });
            console.log('File uploaded', res.data);
        } catch (err) {
            console.error('Failed to upload file', err);
        }
    } else {
        alert("Veuillez entrer un message");
    }
}

As a side note, you should either use async/await (with try/catch) or then/catch. They are just two different syntaxes for promises.

  • Related