How to get the body before uploading file in multer?
Asked Answered
M

5

7

In my project the admins have the ability to upload MP3 files and submit parameters to it like song name.

I decided using multer middleware for handling multipart/form-data.

My problem is req.body.gender returns always undefined, because I have to use it inside the uploadSong listener. I want to upload the song when the gender is zero.

index.ejs

<form method="post" action="/acp" role="publish" enctype="multipart/form-data">
    <div class="form-group">
        <input type="file" name="song" id="song" accept="audio/mpeg">
    </div>

    <input type="checkbox" name="gender" checked data-toggle="toggle" data-on="Male" data-off="Female">
</form>

app.js

var uploadSong = upload.single('song');
app.post('/acp', isLoggedIn, function (req, res) {

    console.log(req.body.gender); // returns "undefined"

    if(req.body.gender == 0) { // returns "undefined"

        uploadSong(req, res, function (err) {
            if (err) {
                res.send('uploaded');
                return;
            }
            res.redirect('/');

        });
    
    }
});
Mojgan answered 15/1, 2017 at 16:38 Comment(0)
P
6

(A) Not possible with multer.

(B) Use busboy. It uses streams to parse the form data and so you can get form elements values before the file upload and the fields are made available as events.

(C) Another solution (if you prefer using multer) is to use multer but add a header to send the value of the parameter to check before file upload. Headers are available as soon as the request reaches the server.

Peti answered 15/1, 2017 at 16:54 Comment(2)
Thanks for answer. I tried busboy, but it seems it doesn't work for express. Then I saw connect-busboy, but I don't know, how to move the uploaded file to a directory. Can you show me an example by editing your post.Mojgan
You saved my life with the 3rd solution! Quite easy one, but not sure how secure it is to create custom header and allow it in the API. Is there any way someone to harm the application by knowing that there is a custom header that is allowed to be passed? I still have authorization with bearer token, thus, I do not think that someone can bypass this.Southey
A
2

by using multer form-data parser you can parse form and access req.body before multer starts just register this app middle-ware:

import * as multer from "multer";

// parse form-data
app.use(multer().any());
Arbitrate answered 2/1, 2021 at 9:34 Comment(1)
I used this, now I can access text fields from other middleware but the image is not getting savedSettle
M
0

This is my sample code, it is woking fine, if you need further explanation please let me know. hope helpful.

var Hotel = require('../models/hotel');
    var path = require('path');
    var multer = require('multer');
    var uplodedImages = [];

    var storageHotelGallery = multer.diskStorage({
      destination: function (req, file, cb) {
        cb(null, './uploads/hotelGallery');
      },
      filename: function (req, file, cb) {
        console.log(req.body);
        var newFileName = Date.now() + path.extname(file.originalname);
        req.newFileName = newFileName;
        cb(null, newFileName);
        uplodedImages.push(newFileName);
      }
    });
    var uploadHotelGallery = multer({ storage: storageHotelGallery}).fields([{ name: 'imgArr', maxCount: 8 }]);

    module.exports = function(router) {
        // ADD HOTEL BASIC DATA TO CREATE HOTEL OBJECT
        router.post('/createHotelStep1', function(req, res) {
            if( req.body.name == null || req.body.name == '' ) {
                res.json({ success: false, message: "Hotel name required" });
                res.end();
            }
            else if( req.body.addressline1 == null || req.body.addressline1 == '' ) {
                res.json({ success: false, message: "Address line 1 is required" });
                res.end();
            }
            else if( req.body.city == null || req.body.city == '') {
                res.json({ success: false, message: "City is required" });
                res.end();
            }
            else {
                var hotel = new Hotel();
                hotel.name = req.body.name;
                hotel.addressline1 = req.body.addressline1;
                hotel.addressline2 = req.body.addressline2;
                hotel.phone = req.body.phone;
                hotel.city = req.body.city;
                hotel.email = req.body.email;
                hotel.save(function(err) {
                    if (err) {
                        res.json({ success: false, message: "Unable to Complete Hotel Step 1" });
                    } else {
                        res.json({ success: true, message: 'Create Hotel Step 1 Complete', _id : hotel._id });
                    }
                });
            }
        });

        router.post('/createHotelGallery', function (req, res, next) {
            uplodedImages = [];
            uploadHotelGallery(req, res, function(err) {
                if(err) {
                    res.json({ success: false, message: 'Could not upload images'});
                    res.end();
                }
                else {
                    Hotel.findOne({ _id:req.body._id }).populate('users').exec(function (err, hotel) {
                    if (err) {
                        res.json({ success: false, message: 'Could not save uploaded images to database'});
                        res.end();  
                    }
                    else {
                        for(var x=0; x<uplodedImages.length; x++)
                            hotel.images.push(uplodedImages[x]);
                        hotel.save();
                        res.json({ success: true, message: 'Gallery image uploaded' });
                        res.end();
                    }
                    });
                }
            });
        });

        return router;
    }
Meletius answered 13/8, 2017 at 16:34 Comment(0)
E
0

This is my sample code, it is woking fine

const upload = multer({
  storage,
  fileFilter(req, file, cb) {
    if(req.body.name===''){
      return cb(new Error('Invalid name'), false)
    }
    const extname = path.extname(file.originalname).toLowerCase() === '.gz'
    const mimetype = file.mimetype === 'application/x-gzip'
    if (mimetype && extname) {
      return cb(null, true)
    } else {
      return cb(new Error('Invalid mime type'), false)
    }
  },
})
Ellipsis answered 11/8, 2022 at 9:44 Comment(0)
P
0

Send as query parameter with the api endpoint. It will be received before the image. 😊

Providential answered 4/2 at 15:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.