react node passing file through axios with multer error 500

Viewed 1189

I am trying to make simple form to pass file and some other data to my server. Later I will try to add database query, but now I don't see any data transferred there, so I am stuck.

I created front-end using react:

const [mainPicture, setMainPicture] = useState(null);
const [pictures, setPictures] = useState([]);
const [name, setName] = useState('Name');
const config = {
    headers: {
        'content-type': 'multipart/form-data'
    }
};

function handleSubmit(e) {
    e.preventDefault();

    const formData = new FormData();
    formData.append('name', name);
    formData.append('mainPicture', mainPicture);

    console.log(formData);

    axios
        .post(
            prefix + '/api/add_project',
            formData, {
            headers: config.headers,
            onUploadProgress: progressEvent => {
                console.log('Upload Progress: ' + Math.round(progressEvent.loaded / progressEvent.total * 100) + '%');
            }
        })
        .then((response) => {
            alert(response);
        })
        .catch((error) => {
            console.log(error);
        });
}

const onDrop = (picture) => {
    setPictures([...pictures, picture]);
};

return (
    <div>
        <form encType="multipart/form-data" onSubmit={handleSubmit}>
            <label>
                Name:
                <input value={name} onChange={(e)=> setName(e.target.value)}
                type="text"/>
            </label>
            <label>
                Project Description:
                <input onChange={(e)=> setDescription(e.target.value)}
                value={description}
                type="text"
                />
            </label>
            <label>
                Project Address:
                <input onChange={(e)=> setAddress(e.target.value)}
                value={address}
                type="text"
                />
            </label>
            <label>
                Used Products:
                <input onChange={(e)=> setUsed(e.target.value)}
                value={used}
                type="text"
                />
            </label>
            <label>
                About Products:
                <input onChange={(e)=> setAbout(e.target.value)}
                value={about}
                type="text"
                />
            </label>
            <input type="file" name="mainPicture" onChange={e=> setMainPicture(e.target.files[0])} />
            <button type="submit">Upload</button>
        </form>
    </div>
);
}

Then I created back-end function with node express in my routes to take api calls from front-end, followed tutorials, but I cant figure out problem here.

var multer = require('multer')
const DIR = './public/images/projects';

const storage = multer.diskStorage({
    destination: (req, file, cb) => {
        cb(null, DIR);
    },
    filename: (req, file, cb) => {
        const fileName = file.originalname.toLowerCase().split(' ').join('-');
        cb(null, fileName)
    }
});

const upload = multer({ storage });

//ADD NEW PROJECT
router.post('/api/add_project', upload.single('mainPicture'), (req, res, next) => {
    console.log("Body ---", req.body);
    console.log('Files--', req.file);
    console.log('file name: ', req.file.name);
});

In my pm2 monit I get this:

enter image description here

WHAT IS THE PROBLEM?

3 Answers

It seems there is an issue with header content-type, they say that header should not be passed, so axios could set it with a proper boudary.

Hope this helps.

As you have defined enctype in the html form, so no need of that in headers. Here is the modified code

const [mainPicture, setMainPicture] = useState(null);
const [pictures, setPictures] = useState([]);
const [name, setName] = useState('Name');
const config = {
    headers: {
        'content-type': 'multipart/form-data'
    }
};

function handleSubmit(e) {
    e.preventDefault();

    const formData = new FormData();
    formData.append('name', name);
    formData.append('mainPicture', mainPicture);

    console.log(formData);

    axios
        .post(
            prefix + '/api/add_project',
            formData, {
            onUploadProgress: progressEvent => {
                console.log('Upload Progress: ' + Math.round(progressEvent.loaded / progressEvent.total * 100) + '%');
            }
        })
        .then((response) => {
            alert(response);
        })
        .catch((error) => {
            console.log(error);
        });
}

const onDrop = (picture) => {
    setPictures([...pictures, picture]);
};

return (
    <div>
        <form encType="multipart/form-data" onSubmit={handleSubmit}>
            <label>
                Name:
                <input value={name} onChange={(e)=> setName(e.target.value)}
                type="text"/>
            </label>
            <label>
                Project Description:
                <input onChange={(e)=> setDescription(e.target.value)}
                value={description}
                type="text"
                />
            </label>
            <label>
                Project Address:
                <input onChange={(e)=> setAddress(e.target.value)}
                value={address}
                type="text"
                />
            </label>
            <label>
                Used Products:
                <input onChange={(e)=> setUsed(e.target.value)}
                value={used}
                type="text"
                />
            </label>
            <label>
                About Products:
                <input onChange={(e)=> setAbout(e.target.value)}
                value={about}
                type="text"
                />
            </label>
            <input type="file" name="mainPicture" onChange={e=> setMainPicture(e.target.files[0])} />
            <button type="submit">Upload</button>
        </form>
    </div>
);
}

Server side code with some modifications

var express = require('express');
var app = express();
var multer = require('multer')
var cors = require('cors');
app.use(cors())

var storage = multer.diskStorage({
      destination: function (req, file, cb) {
      cb(null, 'public')
    },
    filename: function (req, file, cb) {
      cb(null, Date.now() + '-' +file.originalname )
    }
})
var upload = multer({ storage: storage }).single('mainPicture')
app.post('/api/add_project',function(req, res,next) {
     
    upload(req, res, function (err) {
           if (err instanceof multer.MulterError) {
               return res.status(500).json(err)
           } else if (err) {
               return res.status(500).json(err)
           }
      return res.status(200).send(req.file)

    })

});

If you still have issues, follow this step by step guide.

Content-Type header is case sensitive i guess. "Content-Type": "multipart/form-data"

This worked for me

Related