简体   繁体   English

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

[英]How to disable Express BodyParser for file uploads (Node.js)

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. 我正在使用Node.js + Express构建一个Web应用程序,我发现表达公开的连接BodyParser在大多数情况下非常有用。 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. 但是,我希望对多部分表单数据POSTS进行更细粒度的访问 - 我需要将输入流传输到另一台服务器,并且希望避免首先下载整个文件。

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. 但是,因为我正在使用Express BodyParser,所有文件上传都会自动解析并上传,并且在他们访问我的任何功能之前使用“request.files”可用。

Is there a way for me to disable the BodyParser for multipart formdata posts without disabling it for everything else? 有没有办法让我为多部分formdata帖子禁用BodyParser而不禁用其他所有内容?

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提供的功能,但你想为multipart / form-data禁用它,那就是不要express.bodyParser directly使用express.bodyParser directly express.bodyParser is a convenience method that wraps three other methods: express.json , express.urlencoded , and express.multipart . express.bodyParser是一个方便的方法,它包含三个其他方法: express.jsonexpress.urlencodedexpress.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. 这为大多数数据提供了bodysarser的所有好处,同时允许您独立处理formdata上传。

Edit: json and urlencoded are now no longer bundled with Express. 编辑: jsonurlencoded现在不再与Express捆绑在一起。 They are provided by the separate body-parser module and you now use them as follows: 它们由单独的body-parser模块提供,现在您可以按如下方式使用它们:

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

If the need for body parsing depends only on the route itself, the simplest thing is to use bodyParser as a route middleware function on only the routes that need it rather than using it app-wide: 如果身体解析的需要仅取决于路由本身,最简单的方法是仅在需要它的路由上使用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);

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). 当您键入app.use(express.bodyParser()) ,几乎每个请求都将通过bodyParser函数(将执行bodyParser函数取决于Content-Type标头)。

By default, there are 3 headers supported (AFAIR). 默认情况下,支持3个标头(AFAIR)。 You could see sources to be sure. 您可以确定来源。 You can (re)define handlers for Content-Type s with something like this: 您可以(重新)为Content-Type s定义处理程序,如下所示:

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. UPD。

Things have changed in Express 3, so I'm sharing updated code from working project (should be app.use ed before express.bodyParser() ): Express 3中的内容已经发生了变化,所以我正在分享来自工作项目的更新代码(应该 express.bodyParser() 之前使用app.use ed:

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

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. 在Express 3中,您可以将参数传递给bodyParser{defer: true} - 在术语中推迟多部分处理并将Formidable表单对象公开为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 有关更详细的强大事件处理,请参阅https://github.com/felixge/node-formidable

I've faced similar problems in 3.1.1 and found (not so pretty IMO) solution: 我在3.1.1中遇到过类似的问题并且发现(不是那么漂亮的IMO)解决方案:

to disable bodyParser for multipart/form-data: 为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);
});

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: 例如,我正在使用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();
    });

With express v4, and body-parser v1.17 and above, 使用express v4和body-parser v1.17及更高版本,
You can pass a function in the type of bodyParser.json. 您可以传递bodyParser.json type的函数。
body-parser will parse only those inputs where this function returns a truthy value. body-parser将仅解析此函数返回truthy值的那些输入。

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 . 如果content-typemultipart/form-data则该函数返回一个假值。
So, it does not parse the data when the content-type is multipart/form-data . 因此,当content-typemultipart/form-data时,它不会解析multipart/form-data

抛出这是在app.configure之前

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM