将多部分表单上传到另一台服务器

我正在尝试处理我的Node Express服务器上的POST请求,以处理多部分表单上传,在我的情况下,用户正在上传图像。

我想通过我的快速应用程序上传到另一台服务器,这是目前安装使用身体分析器,我也看到不支持多部分bode,而是build议使用一些其他库。

我见过多方,但我不确定如何使用我的客户端应用程序。

在我的客户端代码中,我发布了一个FormData对象,如下所示:

function create(data, name) { var formData = new FormData(); formData.append('file', data, name); return this.parentBase.one('photos').withHttpConfig({transformRequest: angular.identity}).customPOST(formData, undefined, undefined, {'Content-Type': undefined}); } 

注意:我在这里使用了AngularJS的Restangular库

所以从我理解的多方文档看来,我必须处理表单上传事件,并在表单上传完成后再处理。

事情是,我希望我可以直接将上传到另一台服务器。 事先我的客户端应用程序直接调用这个服务器,但我现在试图让所有的东西通过Express路由,这是可能的,还是我必须使用像multiparty?

请求文档给出了一个使用formData的例子,但我不确定这将如何与我见过的多scheme例一起工作。 例如,一旦上传使用mutliparty在Express中完成,那么我是否必须构造另一个formData对象,然后再进行一个请求,否则我将不得不将每个部分传递给另一个服务器?

我很困惑,请有人帮我解决这个问题吗?

谢谢

编辑

好的,我在@yarons注释中看过了multer,这似乎是我想要使用的东西,我试图用我的express路由器设置来使用它,如下所示:

routes.js

 var express = require('express'), router = express.Router(), customers = require('./customers.controller.js'), multer = require('multer'), upload = multer(); router.post('/customers/:customerId/photos/', upload.single('file'), customers.createPhoto); 

controller.js

 module.exports.createPhoto = function(req, res) { console.log(req.file); var options = prepareCustomersAPIHeaders(req); options.formData = req.file; request(options).pipe(res); }; 

在上面的控制器中注销req.file属性我看到:

 { fieldname: 'file', originalname: '4da2e703044932e33b8ceec711c35582.jpg', encoding: '7bit', mimetype: 'image/png', buffer: <Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 00 fa 00 00 00 fa 08 06 00 00 00 88 ec 5a 3d 00 00 20 00 49 44 41 54 78 5e ac bd f9 8f e 6 e9 7a ... >, size: 105868 } 

以下是我通过客户端代码发布的内容:

 var formData = new FormData(); formData.append('file', data, name); return this.parentBase.one('photos').withHttpConfig({transformRequest: angular.identity}).customPOST(formData, undefined, undefined, {'Content-Type': undefined}); 

我所尝试的是合理的吗? 只有它不起作用,我从我尝试发布到服务器的错误。 之前我直接向服务器发送这个请求的时候一切正常,所以我必须在我的Express \ Multer设置中出错

编辑2

好吧,所以经过更多的狩猎,我碰到这篇文章使用多方,我有经理在我的设置工作如此:

 var request = require('request'), multiparty = require('multiparty'), FormData = require('form-data'); module.exports.createPhoto = function(req, res) { //console.log(req.file); var options = prepareCustomersAPIHeaders(req), form = new multiparty.Form(); options.headers['Transfer-Encoding'] = 'chunked'; form.on('part', function(part){ if(part.filename) { var form = new FormData(), r; form.append(part.name, part, {filename: part.filename, contentType: part['content-type']}); r = request(options, function(err, response, body){ res.status(response.statusCode).send(body); }); r._form = form } }); form.on('error', function(error){ console.log(error); }); form.parse(req); }; 

这是现在正在上传我的文件到我的其他服务器,而这个解决scheme的工作,我不喜欢这一行:

 r._form = form 

似乎是分配一个私人表单variables的请求对象,再加上我看不到这样logging在多方网页上的任何东西

任何人都可以提供这个可能的解决scheme的意见

我们使用如下的东西:

客户

 //HTML <input type="file" ng-file-select uploader="info.uploadPath" /> //DIRECTIVES // It is attached to <input type="file" /> element .directive('ngFileSelect', function() { return { link: function($scope, $element) { $element.bind('change', function() { $scope.$emit('file:add', this.files ? this.files : this); }); } }; }) //OTHER var uploadPath = '/api/things/' + $stateParams.thingId + '/add_photo' var uploadInfo = { headers: { 'Authorization': authToken }, form: { title: scope.info.name } } //SERVICE: $rootScope.$on('file:add', function(event, items) { this.addToQueue(items); }.bind(this)); ... addToQueue: function(items) { var length = this.queue.length; angular.forEach(items.length ? items : [items], function(item) { var isValid = !this.filters.length ? true : !!this.filters.filter(function(filter) { return filter.apply(this, [item]); }, this).length; if (isValid) { item = new Item({ url: this.url, alias: this.alias, removeAfterUpload: this.removeAfterUpload, uploader: this, file: item }); this.queue.push(item); } }, this); this.uploadAll(); }, getNotUploadedItems: function() { return this.queue.filter(function(item) { return !item.isUploaded; }); }, /** * Upload a item from the queue * @param {Item|Number} value */ uploadItem: function(value, uploadInfo) { if (this.isUploading) { return; } var index = angular.isObject(value) ? this.getIndexOfItem(value) : value; var item = this.queue[index]; var transport = item.file._form ? '_iframeTransport' : '_xhrTransport'; this.isUploading = true; this[transport](item, uploadInfo); }, uploadAll: function(uploadInfo) { var item = this.getNotUploadedItems()[0]; this._uploadNext = !!item; this._uploadNext && this.uploadItem(item, uploadInfo); }, _xhrTransport: function(item, uploadInfo) { var xhr = new XMLHttpRequest(); var form = new FormData(); var that = this; form.append(item.alias, item.file); angular.forEach(uploadInfo.form, function(value, name) { form.append(name, value); }); xhr.upload.addEventListener('progress', function(event) { var progress = event.lengthComputable ? event.loaded * 100 / event.total : 0; that._scope.$emit('in:progress', item, Math.round(progress)); }, false); xhr.addEventListener('load', function() { xhr.status === 200 && that._scope.$emit('in:success', xhr, item); xhr.status !== 200 && that._scope.$emit('in:error', xhr, item); that._scope.$emit('in:complete', xhr, item); }, false); xhr.addEventListener('error', function() { that._scope.$emit('in:error', xhr, item); that._scope.$emit('in:complete', xhr, item); }, false); xhr.addEventListener('abort', function() { that._scope.$emit('in:complete', xhr, item); }, false); this._scope.$emit('beforeupload', item); xhr.open('POST', item.url, true); angular.forEach(uploadInfo.headers, function(value, name) { xhr.setRequestHeader(name, value); }); xhr.send(form); }, 

服务器

 //things.router app.route('/api/things/:thingId/add_photo') .post(things.uploadPhoto); //things.controller exports.uploadPhoto = function(req, res) { var formidable = require('formidable'); var form = new formidable.IncomingForm(); form.parse(req, function(err, fields, files) { var data = files.qqfile; //actual file is at data.path fs.createReadStream(data.path).pipe(request.put(uploadUrl)); } }