使用强大的和(knox或aws sdk)将文件流式上载到Node.js上的S3
我正在尝试使用或将通过表单提交的文件直接流式上载到AmazonS3存储桶。表单处理是用 我的问题是:如何正确地使用aws sdk(或knox)和这些库的最新特性来处理流 我知道这里已经有人以不同的方式问过这个话题,即:使用强大的和(knox或aws sdk)将文件流式上载到Node.js上的S3,node.js,amazon-s3,formidable,knox-amazon-s3-client,Node.js,Amazon S3,Formidable,Knox Amazon S3 Client,我正在尝试使用或将通过表单提交的文件直接流式上载到AmazonS3存储桶。表单处理是用 我的问题是:如何正确地使用aws sdk(或knox)和这些库的最新特性来处理流 我知道这里已经有人以不同的方式问过这个话题,即: (这是关于overiding form.onPart()的非常有用的公认答案) 但是,我认为答案有点过时和/或离题(即CORS支持,出于各种原因,我现在不想使用它)和/或,最重要的是,没有提及aws sdk(请参阅:)或knox(特别是putStream()或其reada
- (这是关于overiding form.onPart()的非常有用的公认答案)
<form action="/uploadPicture" method="post" enctype="multipart/form-data">
<input name="picture" type="file" accept="image/*">
<input type="submit">
</form>
请求后处理程序:
uploadPicture = (req, res, next) ->
form = new formidable.IncomingForm()
form.parse(req)
form.onPart = (part) ->
if not part.filename
# Let formidable handle all non-file parts (fields)
form.handlePart(part)
else
handlePart(part, form.bytesExpected)
handlePart = (part, fileSize) ->
# aws-sdk version
params =
Bucket: "mybucket"
Key: part.filename
ContentLength: fileSize
Body: part # passing stream object as body parameter
awsS3client.putObject(params, (err, data) ->
if err
console.log err
else
console.log data
)
但是,我得到了以下错误:
{[RequestTimeout:您与服务器的套接字连接在超时期间未被读取或写入。空闲连接将被关闭。]
消息:“您与服务器的套接字连接在超时期间未被读取或写入。空闲连接将被关闭。”,
代码:“请求超时”,
名称:“请求超时”,
状态代码:400,
可检索:false}
以这种方式定制的handlePart()函数的knox版本也会失败:
handlePart = (part, fileSize) ->
headers =
"Content-Length": fileSize
"Content-Type": part.mime
knoxS3client.putStream(part, part.filename, headers, (err, res) ->
if err
console.log err
else
console.log res
)
我还得到一个有400个状态码的大res对象
在这两种情况下,区域都配置为eu-west-1
补充说明:
节点0.10.12
npm的最新版本(1.0.14)
来自npm的最新aws sdk(1.3.1)
npm的最新knox(0.8.3)
直接流式传输到Amazon S3是不可能的:
S3API要求您在创建新文件时提供其大小。在完全接收多部分/表单数据文件之前,此信息不适用于多部分/表单数据文件。这意味着流媒体是不可能的
实际上,form.bytesExpected指的是整个表单的大小,而不是单个文件的大小
因此,在上传到S3之前,数据必须首先到达服务器上的内存或磁盘。使用AWS S3的多端口(作为工作模块)和node Foremble,您可以通过管道将流上传,如下所示:
var-nervouse=require('nervouse');
var http=require('http');
var util=require('util');
var AWS=要求('AWS-sdk');
var config=require('./config');
var s3=新的AWS.s3({
accessKeyId:config.get('S3\u ACCESS\u KEY'),
secretAccessKey:config.get('S3\u SECRET\u KEY'),
apiVersion:‘2006-03-01’
});
var s3Stream=require('s3-upload-stream')(s3);
var bucket=‘bucket name’;
var key='abcdefgh';
http.createServer(函数(req,res){
if(req.url=='/upload'&&req.method.toLowerCase()=='post'){
var form=new.IncomingForm();
表单.on('progress',函数(bytesReceived,bytesExpected){
//log('onprogress',parseInt(100*bytesReceived/bytesExpected),'%”);
});
表单.on('error',函数(err){
console.log('err',err);
});
//此“结束”用于客户端完成上载
//upload.on('uploaded')是指上传时
//在AWS S3上完成
关于('end',function()的表单{
log('end!!!!',参数);
});
在('aborted',function()上的表单{
log('aborted',参数);
});
form.onPart=函数(part){
console.log(“部分”,部分);
//部分看起来像这样
// {
//可读性:对,
//标题:
// {
//“内容处置”:“表单数据;name=“上传”;filename=“00video38.mp4”,
//“内容类型”:“视频/mp4”
// },
//名称:“上传”,
//文件名:“00video38.mp4”,
//mime:“视频/mp4”,
//Transferencode:'二进制',
//传输缓冲区:“”
// }
var start=new Date().getTime();
var upload=s3Stream.upload({
“桶”:桶,
“Key”:part.filename
});
//可选配置
//upload.maxPartSize(20971520);//20MB
上传。concurrentParts(5);
//处理错误。
upload.on('error',函数(error){
console.log('errr',error);
});
upload.on('part',函数(详细信息){
console.log(“部分”,详细信息);
});
upload.on('upload',函数(详细信息){
var end=new Date().getTime();
log('it take',end start);
console.log(“已上载”,详细信息);
});
//也许你可以像这样加上压缩
//part.pipe(压缩).pipe(上载)
管道部分(上传);
};
解析(请求、函数(错误、字段、文件){
res.writeHead(200,{'content-type':'text/plain'});
res.write('收到的上载:\n\n');
res.end(util.inspect({fields:fields,files:files}));
});
返回;
}
//显示文件上传表单
res.writeHead(200,{'content-type':'text/html'});
res.end(
''+
“
”+
“
”+
''+
''
);
}).听(8080);
因为这篇文章太老了,我相信现在支持直接流媒体,所以我花了很多时间阅读关于这个主题的过时答案
如果它对任何人都有帮助的话,我可以直接从客户机流式传输到s3,而无需任何必要
handlePart = (part, fileSize) ->
headers =
"Content-Length": fileSize
"Content-Type": part.mime
knoxS3client.putStream(part, part.filename, headers, (err, res) ->
if err
console.log err
else
console.log res
)
var formidable = require('formidable');
var http = require('http');
var util = require('util');
var AWS = require('aws-sdk');
var config = require('./config');
var s3 = new AWS.S3({
accessKeyId: config.get('S3_ACCESS_KEY'),
secretAccessKey: config.get('S3_SECRET_KEY'),
apiVersion: '2006-03-01'
});
var s3Stream = require('s3-upload-stream')(s3);
var bucket = 'bucket-name';
var key = 'abcdefgh';
http.createServer(function(req, res) {
if (req.url == '/upload' && req.method.toLowerCase() == 'post') {
var form = new formidable.IncomingForm();
form.on('progress', function(bytesReceived, bytesExpected) {
//console.log('onprogress', parseInt( 100 * bytesReceived / bytesExpected ), '%');
});
form.on('error', function(err) {
console.log('err',err);
});
// This 'end' is for the client to finish uploading
// upload.on('uploaded') is when the uploading is
// done on AWS S3
form.on('end', function() {
console.log('ended!!!!', arguments);
});
form.on('aborted', function() {
console.log('aborted', arguments);
});
form.onPart = function(part) {
console.log('part',part);
// part looks like this
// {
// readable: true,
// headers:
// {
// 'content-disposition': 'form-data; name="upload"; filename="00video38.mp4"',
// 'content-type': 'video/mp4'
// },
// name: 'upload',
// filename: '00video38.mp4',
// mime: 'video/mp4',
// transferEncoding: 'binary',
// transferBuffer: ''
// }
var start = new Date().getTime();
var upload = s3Stream.upload({
"Bucket": bucket,
"Key": part.filename
});
// Optional configuration
//upload.maxPartSize(20971520); // 20 MB
upload.concurrentParts(5);
// Handle errors.
upload.on('error', function (error) {
console.log('errr',error);
});
upload.on('part', function (details) {
console.log('part',details);
});
upload.on('uploaded', function (details) {
var end = new Date().getTime();
console.log('it took',end-start);
console.log('uploaded',details);
});
// Maybe you could add compress like
// part.pipe(compress).pipe(upload)
part.pipe(upload);
};
form.parse(req, function(err, fields, files) {
res.writeHead(200, {'content-type': 'text/plain'});
res.write('received upload:\n\n');
res.end(util.inspect({fields: fields, files: files}));
});
return;
}
// show a file upload form
res.writeHead(200, {'content-type': 'text/html'});
res.end(
'<form action="/upload" enctype="multipart/form-data" method="post">'+
'<input type="text" name="title"><br>'+
'<input type="file" name="upload" multiple="multiple"><br>'+
'<input type="submit" value="Upload">'+
'</form>'
);
}).listen(8080);
const fileUploadStream = (req, res) => {
//get "body" args from header
const { id, fn } = JSON.parse(req.get('body'));
const Key = id + '/' + fn; //upload to s3 folder "id" with filename === fn
const params = {
Key,
Bucket: bucketName, //set somewhere
Body: req, //req is a stream
};
s3.upload(params, (err, data) => {
if (err) {
res.send('Error Uploading Data: ' + JSON.stringify(err) + '\n' + JSON.stringify(err.stack));
} else {
res.send(Key);
}
});
};
...
const params = {
Key,
Bucket: bucketName,
Body: req,
ContentType: 'image/jpg'
};
s3.upload(params, (err, data) => {
if (err) return err;
console.log(data);
});
...