通过管道将多部分表单上载到另一个服务器
Pipe multipart form uploads to another server
我正试图在Node Express服务器上处理POST请求,以处理多部分表单上传,在我的情况下,用户正在上传图像。
我想通过我的Express应用程序将上传到另一台服务器,该应用程序目前被设置为使用body解析器,我也看到它不支持多部分bodes,而是建议使用其他一些库。
我见过多方参与,但我不确定如何在客户端应用程序中使用它。
在我的客户端代码中,我发布了一个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路由所有内容,这可能吗,还是我必须使用类似多方的东西?
请求文档给出了一个使用formData的示例,但我不确定这将如何与我看到的多方示例一起使用。例如,一旦在Express中使用mutliparty完成上传,我是否必须构建另一个formData对象,然后用它发出进一步的请求,或者我是否必须将每个部分管道连接到另一个服务器?
我很困惑,有人能帮我澄清一下吗?
感谢
编辑
好吧,我看了一下下面@yarons评论中的multer,这似乎是我想要使用的东西,我已经尝试将其用于我的快速路由器设置,如下所示:
路由.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);
};
这是现在为我上传文件,为我的另一个服务器预期,虽然这个解决方案工作,我不喜欢行:
r._form = form
似乎正在为请求对象分配一个私有表单变量,而且我在多方页面上看不到任何以这种方式记录的内容
有人能对这个可能的解决方案发表意见吗?
我们使用以下内容:
客户端
//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));
}
}
- HTML外部javascript加载另一个javascript
- 正在下载文件,同时加载另一个页面
- 为什么当我上传文件并点击更多上传另一个文件的第一个删除
- .replaceWith 无法使用 .click 函数加载另一个值
- 如何使用onclick事件点击一个图像,并让它更改同一网页上的另一个图像
- 如何打开弹出窗口并重新加载另一个页面
- 收到事件时加载另一个.html页面
- 如何将剑道UI窗口与页面上的另一个元素对齐
- jQuery-检查外部页面上是否存在DIV,如果存在,则加载DIV,否则加载另一个
- 禁用“基于同一行上的另一个元素进行选择”
- 在简单模式中,取消单击时不会调用onClose事件..当我在simple-modal上加载另一个jquery对话框时
- Highcharts可点击列打开同一网站上的另一个页面
- Android WebView:在javascript中,有没有一种方法可以加载另一个javascript文件,并为堆栈
- 在画布上绘制另一个图像
- 我的按钮中的函数不会重新加载另一个函数
- 使用隐藏字段 ID 选择器加载另一个字段中的文本
- jQuery:将图像随机填充到页面上的另一个图像上
- 使用 JavaScript 在 :hover 上获取另一个元素的 innerHTML
- 从Objective C上的另一个JS(CSS)文件加载JS(CSS)文件
- 将Iframe用于服务器上的另一个文件会使当前页面加载比直接在页面上加载更快吗