2012-07-02 3 views
57

Кажется, что это должен быть довольно простой вопрос, но мне очень трудно понять, как подойти к нему.Как отключить Express BodyParser для загрузки файлов (Node.js)

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

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

Есть ли способ отключить BodyParser для сообщений multipart formdata, не отключая его для всего остального?

+1

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

ответ

16

Whe n вы вводите 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.

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

Или вы можете 'delete express.bodyParser.parse ['multipart/form-data'];' ** перед ** 'app.use (express.bodyParser())' as @jwerre – elmigranto

61

Если вам необходимо использовать функциональные возможности, предоставляемые 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 для большинства данных, позволяя обрабатывать FormData загрузки самостоятельно.

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

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

Или вы можете определить собственный 'bodyParser' для заголовка Content-Type' multipart/form-data': 'require ('express'). BodyParser.parse ['multipart/form-data'] = function yourHandler (req, options , next) ... ' – elmigranto

+0

Это еще лучше - если вы представите это как ответ с образцом короткого кода, я сделаю его принятым ответом для потока. Замечательно, насколько сложно найти простую информацию. Благодаря! – Myk

+0

Это действительно удобно знать, особенно для истончения зависимостей установленных приложений! – wprl

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); 
+1

Отличный ответ. – antonio081014

1

бросить это, прежде app.configure

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

Я пробовал это в разных частях моего кода, и это всегда приводило к сбою приложения немедленно. – Myk

+0

Вы положили его перед тем, как создать экземпляр вашего тела? Если нет, вы должны это сделать. – jwerre

+0

для меня тоже :( – nick

15

в экспресс 3, вы можете передать параметр в bodyParser в {defer: true} - который в перспективе нескольких отсрочивает обработки детали и предоставляет объект Formableable form как 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

+0

Я не уверен, что я не делаю ничего плохого, но прослушиватели событий не будут работать в моем случае. Я проверил исходный код multipart.js и вызовы промежуточного программного обеспечения после разбора целых данных (и нет возможность вызывать его дважды), поэтому события выходят перед назначением в вашем примере – JakubKnejzlik

+2

Кажется, что Formidable больше не включен в Express 4. См. https://github.com/felixge/node-formidable/issues/264 –

4

Я сталкивался с подобными проблемами в 3.1.1 и нашел (не так красиво IMO) решение:

отключить 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(); 
    }); 
Смежные вопросы