如何为文件上传禁用 Express BodyParser (Node.js)

IT技术 javascript node.js file-upload express connect
2021-03-18 17:15:49

这似乎应该是一个相当简单的问题,但我很难弄清楚如何解决它。

我正在使用 Node.js + Express 构建一个 Web 应用程序,我发现 express 公开的 connect BodyParser 在大多数情况下非常有用。但是,我希望对多部分表单数据 POSTS 进行更精细的访问 - 我需要将输入流通过管道传输到另一台服务器,并希望避免先下载整个文件。

但是,因为我使用的是 Express BodyParser,所以所有文件上传都会在它们到达我的任何函数之前自动解析并上传并使用“request.files”可用。

有没有办法让我禁用多部分表单数据帖子的 BodyParser 而不禁用其他所有内容?

6个回答

如果您需要express.bodyParser使用express.bodyParser directly. express.bodyParser是一个封装其它三种方法一个方便的方法:express.jsonexpress.urlencoded,和express.multipart

所以与其说

app.use(express.bodyParser())

你只需要说

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

这为您提供了大多数数据的 bodyparser 的所有好处,同时允许您独立处理表单数据上传。

编辑: jsonurlencoded现在不再与快递捆绑在一起。它们由单独的body-parsermodule提供,您现在可以按如下方式使用它们:

bodyParser = require("body-parser")
app.use(bodyParser.json())
   .use(bodyParser.urlencoded())
或者您可以bodyParsermultipart/form-dataContent-Type 标头定义自己require('express').bodyParser.parse['multipart/form-data'] = function yourHandler(req, options, next)...
2021-04-22 17:15:49
那就更好了 - 如果您将其作为带有简短代码示例的答案提交,我会将其设为该线程的可接受答案。值得注意的是,要找到这条简单的信息是多么困难。谢谢!
2021-05-03 17:15:49
知道这真的很方便,特别是对于减少已安装应用程序的依赖项!
2021-05-18 17:15:49

如果正文解析的需要仅取决于路由本身,最简单的方法是bodyParser仅在需要它的路由上用作路由中间件功能,而不是在应用程序范围内使用它:

var express=require('express');
var app=express.createServer();
app.post('/body', express.bodyParser(), function(req, res) {
    res.send(typeof(req.body), {'Content-Type': 'text/plain'});
});
app.post('/nobody', function(req, res) {
    res.send(typeof(req.body), {'Content-Type': 'text/plain'});
});
app.listen(2484);

当您键入 时app.use(express.bodyParser()),几乎每个请求都会通过bodyParser函数(执行哪个取决于Content-Type标头)。

默认情况下,支持 3 个标头 (AFAIR)。你可以看到消息来源。您可以(重新)定义Content-Types 的处理程序,如下所示:

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();
}


更新。

Express 3 中的事情发生了变化,所以我正在分享来自工作项目的更新代码(应该在app.useed之前 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);
  };
};

还有一些伪代码,关于原始问题:

function disableParserForContentType(req, res, next) {
  if (req.contentType in options.contentTypes) {
    req._body = true;
    next();
  }
}
或者你可以delete express.bodyParser.parse['multipart/form-data']; app.use(express.bodyParser())的@jwerre建议。
2021-05-07 17:15:49

在 Express 3 中,您可以将参数传递给bodyParseras {defer: true}- 这在术语中推迟多部分处理并将 Formidable 表单对象公开为 req.form。这意味着您的代码可以是:

...
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){


    })
}

有关更详细的强大事件处理,请参阅https://github.com/felixge/node-formidable

我不确定我是否没有做错任何事情,但事件侦听器在我的情况下不起作用。我已经检查了 multipart.js 的源代码和中间件在解析整个数据后调用 next (并且不可能调用它两次),所以在你的例子中分配之前发出事件
2021-04-25 17:15:49
似乎 Formidable 不再包含在 Express 4 中。参见github.com/felixge/node-formidable/issues/264
2021-05-20 17:15:49

我在 3.1.1 中遇到过类似的问题,并找到了(不是很漂亮的 IMO)解决方案:

为 multipart/form-data 禁用 bodyParser:

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);
});

并解析内容:

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
});

例如,我正在使用节点多方,其中自定义代码应如下所示:

    var form = new multiparty.Form();

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

    form.parse(req, function(err, fields, files) {
       //...next();
    });