Вопрос по javascript, node.js, express, connect, file-upload – Как отключить Express BodyParser для загрузки файлов (Node.js)

58

Кажется, это должен быть довольно простой вопрос, но мне очень трудно понять, как к нему подойти.

Я использую Node.js + Express для создания веб-приложения, и я считаю, что Connect BodyParser, который предоставляет Express, очень полезен в большинстве случаев. Однако мне бы хотелось иметь более детальный доступ к многостраничным ПОСТ-данным формы по мере их поступления - мне нужно перенаправить входной поток на другой сервер, и сначала я хочу избежать загрузки всего файла.

Однако поскольку я использую Express BodyParser, все загружаемые файлы анализируются автоматически, загружаются и доступны с использованием & quot; request.files & quot; до того, как они дойдут до любой из моих функций.

Есть ли способ для меня отключить BodyParser для составных сообщений форм-данных, не отключая его для всего остального?

Aaaarg! Я только что потратил целый день, пытаясь понять, почему я не могу загрузить файлы, когда образец приложения (без Express, но также, очевидно, со многими другими отличиями) работал идеально. ОказываетсяbodyParser виновник Спасибо за вопрос. meloncholy

Ваш Ответ

7   ответов
2


Вы можете передать функцию вtype bodyParser.json.
body-parser будет анализировать только те входные данные, где эта функция возвращает истинное значение.

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

В приведенном выше коде,
функция возвращает ложное значение, еслиcontent-type являетсяmultipart/form-data.
Таким образом, он не анализирует данные, когдаcontent-type являетсяmultipart/form-data.

27

проще всего воспользоваться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);
Отличный ответ.
4

ое) решение:

отключить bodyParser для 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);
});

и для разбора содержимого:

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

express.bodyParser но вы хотите отключить его для multipart / form-data, хитрость в том, чтобы не использоватьexpress.bodyParser directly. express.bodyParser это удобный метод, который включает три других метода:express.json, express.urlencoded, а такжеexpress.multipart.

Так что вместо того, чтобы сказать

app.use(express.bodyParser())

тебе просто нужно сказать

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

Это дает вам все преимущества bodyparser для большинства данных, в то же время позволяя вам независимо обрабатывать загрузку форм-данных.

Edit: json а такжеurlencoded больше не связаны с Express. Они предоставляются отдельнымтело-анализатор модуль и теперь вы используете их следующим образом:

bodyParser = require("body-parser")
app.use(bodyParser.json())
   .use(bodyParser.urlencoded())
Или вы можете определить свой собственныйbodyParser заmultipart/form-data Заголовок Content-Type:require('express').bodyParser.parse['multipart/form-data'] = function yourHandler(req, options, next)...
Это должен быть принятый ответ! Чистый & amp; Чисто
Это даже лучше - если вы отправите это как ответ с коротким образцом кода, я сделаю его приемлемым ответом для потока. Замечательно, как трудно было найти эту простую информацию. Спасибо! Myk
Это очень удобно знать, особенно для уменьшения зависимости подключаемых приложений!
@Myk Я отредактировал ответ для большей ясности; надеюсь, вы можете пометить его как принятый сейчас.
16

app.use(express.bodyParser()), почти каждый запрос будет проходитьbodyParser функции (какая из них будет выполняться зависит отContent-Type заголовок).

По умолчанию поддерживается 3 заголовка (AFAIR). Вы могли видеть источники, чтобы быть уверенным. Вы можете (пере) определить обработчики дляContent-Typeс чем-то вроде этого:

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.

В Express 3 все изменилось, поэтому я делюсь обновленным кодом из рабочего проекта (должно бытьapp.useиздание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);
  };
};

И некоторый псевдокод относительно оригинального вопроса:

function disableParserForContentType(req, res, next) {
  if (req.contentType in options.contentTypes) {
    req._body = true;
    next();
  }
}
Или вы можетеdelete express.bodyParser.parse['multipart/form-data']; before app.use(express.bodyParser()) как предложил @jwerre.
15

bodyParser как{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

Кажется, что Formidable больше не входит в Express 4. См.github.com/felixge/node-formidable/issues/264
Я не уверен, что не делаю ничего плохого, но слушатели событий не будут работать в моем случае. Я проверил исходный код multipart.js и вызовов промежуточного программного обеспечения после синтаксического анализа целых данных (и нет возможности вызвать их дважды), поэтому в вашем примере события генерируются перед назначением
1

delete express.bodyParser.parse['multipart/form-data'];
у меня это тоже вылетает :(
Я пробовал это в разных частях моего кода, и это всегда приводило к немедленному падению приложения. Myk
Вы положили его до того, как создали экземпляр вашего bodyParser? Если нет, вы должны это сделать.

Похожие вопросы