最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - NodeJS Multer validate fields before upload - Stack Overflow

programmeradmin5浏览0评论

I'm trying to validation my form before i upload images but i getting empty string on my middleware

const upload = multer({
  storage: storage
});

router.post('/upload', formsValidation, upload.fields([{

  name: 'images',
  maxCount: 20

}, {

  name: 'imageMain',
  maxCount: 1

}]), function(req, res, next) {
  code...

});

heres my middleware:

function formsValidation (req, res, next) {

  console.log(req.body) //getting empty array here
  return next();
}

i know that i can use fileFilter from multer but some times i dont have any images to upload just string to store and validate, i have tried to parse the req.body from multipart/form-data to string then validate and use next() but i get a range error, any ideia how can i solve this?

I'm trying to validation my form before i upload images but i getting empty string on my middleware

const upload = multer({
  storage: storage
});

router.post('/upload', formsValidation, upload.fields([{

  name: 'images',
  maxCount: 20

}, {

  name: 'imageMain',
  maxCount: 1

}]), function(req, res, next) {
  code...

});

heres my middleware:

function formsValidation (req, res, next) {

  console.log(req.body) //getting empty array here
  return next();
}

i know that i can use fileFilter from multer but some times i dont have any images to upload just string to store and validate, i have tried to parse the req.body from multipart/form-data to string then validate and use next() but i get a range error, any ideia how can i solve this?

Share Improve this question edited Jan 9, 2018 at 17:35 Devang Naghera 7066 silver badges13 bronze badges asked Jan 9, 2018 at 17:29 JohnJohn 5333 gold badges9 silver badges19 bronze badges 2
  • req.file ? 4 more to go – yBrodsky Commented Jan 9, 2018 at 17:36
  • getting undefined from req.file – John Commented Jan 9, 2018 at 17:41
Add a ment  | 

3 Answers 3

Reset to default 1

This is from Multer's docs:

Note that req.body might not have been fully populated yet. It depends on the order that the client transmits fields and files to the server.

That's mean you have to call formsValidation just after multer midlleware, to make sure that all posted data have been fully populated

router.post('/upload', upload.fields([{

    name: 'images',
    maxCount: 20

}, {

    name: 'imageMain',
    maxCount: 1

}]), formsValidation, function(req, res, next) {
    code...
});

Problem

Before the call to Multer middleware (upload.fields(...)), the request body hasn't even begun to be parsed yet. The Express req object you receive in your formValidation() middleware is only an instance of http.IningMessage, which itself is an instance of a stream.Readable, whose data hasn't been consumed yet. Only once you call the Multer upload.fields(...) middleware (or any other middleware provided by Multer), the req stream is piped through Busboy (the multipart/form-data request parser used by Multer), and the fields & files get parsed and populated (in order of their appearance) to req.body.

Solution

Unfortunately, Multer doesn't provide functionality to handle field events, only files. You can validate the fields that were populated in req.body before a file was received (as outlined in this Github issue), however:

  1. That strongly ties your validation implementation with Multer's API;
  2. As you noted yourself, there can be cases where you send/received no files, but still want to validate fields.
  3. Validation will reduntantly run each time a file is encountered – if you have 3 files, validation on req.body will run three times. This shouldn't have a huge effect on performance, but still, it's not very elegant.

I'm not aware of any other workaround using Multer. That's why I've written pechkin to solve this exact problem.

  • pechkin.parseFormData() returns a Promise that resolves when all fields are parsed, and if the first file is encountered (or the request ended).
  • The promise contains a populated fields object, and a files AsyncIterator/AsyncIterable.
  • No need to provide storage engines, file handlers, event listeners, etc.

This means you can perform validation on the fields object, and only then have to mess with files – the files won't be parsed, processed, written to memory, saved anywhere, etc., until you decide to do so.

// ESM
import { parseFormData } from 'pechkin';

// CommonJS
const { parseFormData } = require('pechkin');

// ...

app.post(
  '/upload',
  pechkinFileUpload(/* ...optional configs */),
  formsValidation,
  (req, res, next) => {
    // Process files and/or fields (`req.files`) ...
  }
);

function formsValidation (req, res, next) {
  console.log(req.body) // No longer empty! Populated with all fields (see note)
  return next();
}

// Just a utility function to follow Express' middleware style
function pechkinFileUpload (/* ...optional configs */) {
  return async (req, res, next) => {
    try {
      const { fields, files } = await parseFormData(req, /* ...optional configs */);

      req.body = fields;
      req.files = files;

      return next();
    } catch (err) {
      return next(err);
    }
  }
}

No 'multer'! I had to redo a lot of my work because if you have a validator, then 'multer' will first save the file, parse the data, and only then check the first and last name. And if the user refuses to register, the image will remain on the server. And the 'express-form-data' module - accepts data that arrives from the form in FormData format and makes it understandable for us.

let parse_formdata = require('express-form-data');
let os = require('os');

let options_parse_formdata = {
    uploadDir: os.tmpdir(),
    autoClean: true
};

app.use(parse_formdata.parse(options_parse_formdata));
app.use(parse_formdata.format());
app.use(parse_formdata.stream());
app.use(parse_formdata.union());

app.post('/add', async function(req, res, next){

    let file_name = new Date().getTime().toString() + (Math.random()*900+100).toFixed(0) + '.png';

    let read_stream = fs.createReadStream(req.body.avatar.path);
    let write_stream  = fs.createWriteStream('./static/images/' + file_name);

    read_stream.pipe(write_stream);

    write_stream.on('finish', async () => {
        console.log('Файл сохранён на сервер.');
    });

});
发布评论

评论列表(0)

  1. 暂无评论