【问题标题】:How to disable Express BodyParser for file uploads (Node.js)如何为文件上传禁用 Express BodyParser (Node.js)
【发布时间】:2012-07-02 23:28:53
【问题描述】:

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

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

但是,因为我使用的是 Express BodyParser,所以所有文件上传都会自动解析并使用“request.files”上传并可用,然后才能使用我的任何功能。

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

【问题讨论】:

  • 啊啊啊!我刚刚花了一天多的时间试图弄清楚为什么当示例应用程序(没有 Express,但显然还有许多其他差异)运行良好时我无法上传文件。原来bodyParser 是罪魁祸首。感谢您提出这个问题。

标签: javascript node.js file-upload express connect


【解决方案1】:

如果您需要使用express.bodyParser 提供的功能,但又想为 multipart/form-data 禁用它,诀窍是不要使用express.bodyParser directlyexpress.bodyParser 是一种方便的方法,它封装了其他三个方法:express.jsonexpress.urlencodedexpress.multipart

所以不要说

app.use(express.bodyParser())

你只需要说

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

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

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

bodyParser = require("body-parser")
app.use(bodyParser.json())
   .use(bodyParser.urlencoded())

【讨论】:

  • 或者您可以为multipart/form-data 定义自己的bodyParser Content-Type 标头:require('express').bodyParser.parse['multipart/form-data'] = function yourHandler(req, options, next)...
  • 那就更好了 - 如果您将其作为带有简短代码示例的答案提交,我将使其成为该线程的公认答案。很明显,这条简单的信息是多么难以找到。谢谢!
  • 这真的很方便知道,尤其是对于减少已安装应用程序的依赖关系!
【解决方案2】:

如果对body解析的需求只依赖于路由本身,最简单的方法是只在需要它的路由上使用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);

【讨论】:

    【解决方案3】:

    在 app.configure 之前抛出这个

    delete express.bodyParser.parse['multipart/form-data'];
    

    【讨论】:

    • 我在代码的各个部分都试过了,它总是让应用程序立即崩溃。
    • 你在实例化你的bodyParser之前放了吗?如果不是,你应该这样做。
    【解决方案4】:

    当你输入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 建议。
    【解决方案5】:

    在 Express 3 中,您可以将参数作为 {defer: true} 传递给 bodyParser - 这会延迟多部分处理并将强大的表单对象公开为 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 的源代码和中间件调用(并且不可能调用它两次),因此在您的示例中分配之前会发出事件
    • Express 4 中似乎不再包含 Formidable 了。见github.com/felixge/node-formidable/issues/264
    【解决方案6】:

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

    例如,我正在使用 node-multiparty,其中自定义代码应如下所示:

        var form = new multiparty.Form();
    
        form.on('file',function(name,file){
           //...per file event handling
        });     
    
        form.parse(req, function(err, fields, files) {
           //...next();
        });
    

    【讨论】:

      【解决方案7】:

      使用 express v4 和 body-parser v1.17 及更高版本,
      您可以在 bodyParser.json 的type 中传递一个函数。
      body-parser 将仅解析此函数返回真实值的那些输入。

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

      在上面的代码中,
      如果content-typemultipart/form-data,则该函数返回一个假值。
      因此,当content-typemultipart/form-data 时,它不会解析数据。

      【讨论】:

        猜你喜欢
        • 2017-08-12
        • 1970-01-01
        • 2016-05-15
        • 1970-01-01
        • 1970-01-01
        • 2014-11-30
        • 1970-01-01
        • 2012-12-11
        • 2015-07-18
        相关资源
        最近更新 更多