How to disable Express BodyParser for file uploads

2019-01-08 04:46发布

This seems like it should be a fairly simple question, but I'm having a really hard time figuring out how to approach it.

I'm using Node.js + Express to build a web application, and I find the connect BodyParser that express exposes to be very useful in most cases. However, I would like to have more granular access to multipart form-data POSTS as they come - I need to pipe the input stream to another server, and want to avoid downloading the whole file first.

Because I'm using the Express BodyParser, however, all file uploads are parsed automatically and uploaded and available using "request.files" before they ever get to any of my functions.

Is there a way for me to disable the BodyParser for multipart formdata posts without disabling it for everything else?

7条回答
做自己的国王
2楼-- · 2019-01-08 05:07

throw this is before app.configure

delete express.bodyParser.parse['multipart/form-data'];
查看更多
我只想做你的唯一
3楼-- · 2019-01-08 05:10

When you type app.use(express.bodyParser()), almost each request will go through bodyParser functions (which one will be executed depends on Content-Type header).

By default, there are 3 headers supported (AFAIR). You could see sources to be sure. You can (re)define handlers for Content-Types with something like this:

var express = require('express');
var bodyParser = express.bodyParser;

// redefine handler for Content-Type: multipart/form-data
bodyParser.parse('multipart/form-data') = function(req, options, next) {
  // parse request body your way; example of such action:
  // https://github.com/senchalabs/connect/blob/master/lib/middleware/multipart.js

  // for your needs it will probably be this:
  next();
}


upd.

Things have changed in Express 3, so I'm sharing updated code from working project (should be app.useed before express.bodyParser()):

var connectUtils = require('express/node_modules/connect/lib/utils');

/**
 * Parses body and puts it to `request.rawBody`.
 * @param  {Array|String} contentTypes Value(s) of Content-Type header for which
                                       parser will be applied.
 * @return {Function}                  Express Middleware
 */
module.exports = function(contentTypes) {
  contentTypes = Array.isArray(contentTypes) ? contentTypes
                                             : [contentTypes];
  return function (req, res, next) {
    if (req._body)
      return next();

    req.body = req.body || {};

    if (!connectUtils.hasBody(req))
      return next();

    if (-1 === contentTypes.indexOf(req.header('content-type')))
      return next();

    req.setEncoding('utf8');  // Reconsider this line!
    req._body   = true;       // Mark as parsed for other body parsers.
    req.rawBody = '';

    req.on('data', function (chunk) {
      req.rawBody += chunk;
    });

    req.on('end', next);
  };
};

And some pseudo-code, regarding original question:

function disableParserForContentType(req, res, next) {
  if (req.contentType in options.contentTypes) {
    req._body = true;
    next();
  }
}
查看更多
时光不老,我们不散
4楼-- · 2019-01-08 05:16

If you need to use the functionality provided by express.bodyParser but you want to disable it for multipart/form-data, the trick is to not use express.bodyParser directly. express.bodyParser is a convenience method that wraps three other methods: express.json, express.urlencoded, and express.multipart.

So instead of saying

app.use(express.bodyParser())

you just need to say

app.use(express.json())
   .use(express.urlencoded())

This gives you all the benefits of the bodyparser for most data while allowing you to handle formdata uploads independently.

Edit: json and urlencoded are now no longer bundled with Express. They are provided by the separate body-parser module and you now use them as follows:

bodyParser = require("body-parser")
app.use(bodyParser.json())
   .use(bodyParser.urlencoded())
查看更多
疯言疯语
5楼-- · 2019-01-08 05:20

Within Express 3, you can pass parameter to the bodyParser as {defer: true} - which in term defers multipart processing and exposes the Formidable form object as req.form. Meaning your code can be:

...
app.use(express.bodyParser({defer: true}));

...
// your upload handling request 
app.post('/upload', function(req, res)) {
    var incomingForm = req.form  // it is Formidable form object

    incomingForm.on('error', function(err){

          console.log(error);  //handle the error

    })

    incomingForm.on('fileBegin', function(name, file){

         // do your things here when upload starts
    })


    incomingForm.on('end', function(){

         // do stuff after file upload
    });

    // Main entry for parsing the files
    // needed to start Formidables activity
    incomingForm.parse(req, function(err, fields, files){


    })
}

For more detailed formidable event handling refer to https://github.com/felixge/node-formidable

查看更多
Root(大扎)
6楼-- · 2019-01-08 05:20

With express v4, and body-parser v1.17 and above,
You can pass a function in the type of bodyParser.json.
body-parser will parse only those inputs where this function returns a truthy value.

app.use(bodyParser.json({
    type: function(req) {
        return req.get('content-type').indexOf('multipart/form-data') !== 0;
    },
}));

In the above code,
the function returns a falsy value if the content-type is multipart/form-data.
So, it does not parse the data when the content-type is multipart/form-data.

查看更多
甜甜的少女心
7楼-- · 2019-01-08 05:25

I've faced similar problems in 3.1.1 and found (not so pretty IMO) solution:

to disable bodyParser for multipart/form-data:

var bodyParser = express.bodyParser();
app.use(function(req,res,next){
    if(req.get('content-type').indexOf('multipart/form-data') === 0)return next();
    bodyParser(req,res,next);
});

and for parsing the content:

app.all('/:token?/:collection',function(req,res,next){
    if(req.get('content-type').indexOf('multipart/form-data') !== 0)return next();
    if(req.method != 'POST' && req.method != 'PUT')return next();
    //...use your custom code here
});

for example I'm using node-multiparty where the custom code should look like this:

    var form = new multiparty.Form();

    form.on('file',function(name,file){
       //...per file event handling
    });     

    form.parse(req, function(err, fields, files) {
       //...next();
    });
查看更多
登录 后发表回答