使用 node.js 保存存储在 s3 上的图像?
Posted
技术标签:
【中文标题】使用 node.js 保存存储在 s3 上的图像?【英文标题】:Saving an image stored on s3 using node.js? 【发布时间】:2012-12-08 09:49:14 【问题描述】:我正在尝试编写一个使用 node.js 将图像存储在 s3 上的图像服务器。上传图像工作正常,我可以使用 s3 浏览器客户端正确下载和查看它(我使用的是 dragondisk,具体来说,但我也已经成功下载了其他图像),但是当我使用 node 下载它并尝试要将其写入磁盘,我无法打开文件(它说它可能已损坏或使用预览无法识别的文件格式)。我正在使用 amazon sdk for node 和 fs 来编写文件。我知道您可以将可选编码传递给 fs.writeFile,但我已经尝试了所有方法,但它不起作用。我还尝试在 putObject 上设置 ContentType,在 getObject 上设置 ResponseContentType,以及 ContentEncoding 和 ResponseContentEncoding(以及所有这些东西的各种组合)。结果相同。这是一些代码:
var AWS = require('aws-sdk')
, gm = require('../lib/gm')
, uuid = require('node-uui')
, fs = require('fs');
AWS.config.loadFromPath('./amazonConfig.json');
var s3 = new AWS.S3();
var bucket = 'myBucketName'; // There's other logic here to set the bucket name.
exports.upload = function(req, res)
var id = uuid.v4();
gm.format("/path/to/some/image.jpg", function(format)
var key = req.params.dir + "/" + id + "/default." + format;
fs.readFile('/path/to/some/image.jpg', function(err, data)
if (err) console.warn(err);
else
s3.client.putObject(
Bucket: bucket,
Key: key,
Body: data,
ContentType: 'image/jpeg'
// I've also tried adding ContentEncoding (in various formats) here.
).done(function(response)
res.status(200).end(JSON.stringify(ok:1, id: id));
).fail(function(response)
res.status(response.httpResponse.statusCode).end(JSON.stringify((err: response)));
);
);
);
;
exports.get = function(req, res)
var key = req.params.dir + "/" + req.params.id + "/default.JPEG";
s3.client.getObject(
Bucket: bucket,
Key: key,
ResponseContentType: 'image/jpeg'
// Tried ResponseContentEncoding here in base64, binary, and utf8
).done(function(response)
res.status(200).end(JSON.stringify(ok:1, response: response));
var filename = '/path/to/new/image/default.JPEG';
fs.writeFile(filename, response.data.Body, function(err)
if (err) console.warn(err);
// This DOES write the file, just not as an image that can be opened.
// I've tried pretty much every encoding as the optional third parameter
// and I've matched the encodings to the ResponseContentEncoding and
// ContentEncoding above (in case it needs to be the same)
);
).fail(function(response)
res.status(response.httpResponse.statusCode).end(JSON.stringify(err: response));
);
;
顺便说一句,我使用 express 进行路由,所以这就是 req.params 的来源。
【问题讨论】:
我刚刚发现,如果我将“base64”作为编码传递给 fs.readFile() 和 fs.writeFile(),则相反。我可以使用我的服务下载和查看图像,但如果我使用 s3 浏览器客户端下载它,则无法查看它。有什么方法可以同时做到这两点吗? 【参考方案1】:对于仍在为这个问题苦苦挣扎的人。这是我在原生 aws-sdk 中使用的方法。
var AWS = require('aws-sdk');
AWS.config.loadFromPath('./s3_config.json');
var s3Bucket = new AWS.S3( params: Bucket: 'myBucket' );
在您的路由器方法中:- ContentType 应该设置为图片文件的内容类型
buf = new Buffer(req.body.imageBinary.replace(/^data:image\/\w+;base64,/, ""),'base64')
var data =
Key: req.body.userId,
Body: buf,
ContentEncoding: 'base64',
ContentType: 'image/jpeg'
;
s3Bucket.putObject(data, function(err, data)
if (err)
console.log(err);
console.log('Error uploading data: ', data);
else
console.log('succesfully uploaded the image!');
);
s3_config.json 文件是:-
"accessKeyId":"xxxxxxxxxxxxxxxx",
"secretAccessKey":"xxxxxxxxxxxxxx",
"region":"us-east-1"
【讨论】:
我从s3下载的图片损坏了。你知道这可能是什么原因吗?【参考方案2】:好的,经过大量的试验和错误后,我想出了如何做到这一点。我最终切换到了 knox,但据推测,您可以对 aws-sdk 使用类似的策略。这种解决方案让我说,“必须有比这更好的方法”,但目前我对任何可行的方法都很满意。
var imgData = "";
client.getFile(key, function(err, fileRes)
fileRes.on('data', function(chunk)
imgData += chunk.toString('binary');
).on('end', function()
res.set('Content-Type', pic.mime);
res.set('Content-Length', fileRes.headers['content-length']);
res.send(new Buffer(imgData, 'binary'));
);
);
getFile()
将数据块作为缓冲区返回。有人会认为您可以将结果直接传送到前端,但无论出于何种原因,这是我可以让服务正确返回图像的唯一方法。将缓冲区写入二进制字符串感觉是多余的,只是将其写回缓冲区,但是嘿,如果它有效,它就有效。如果有人找到更有效的解决方案,我很乐意听到。
【讨论】:
S3 需要流的长度。也就是说,这有点像 hack,但是如果您在 putObject 调用中将传递给 S3 Body 的流上设置 .length 属性,那就可以了。 @ChristopherWJRueber 所以将流的.length
属性传递给参数ContentLength
可以解决这个问题吗?【参考方案3】:
uploadfile(file, filename, folder)
const bucket = new S3(
accessKeyId: 'enter your access key id here',
secretAccessKey: 'enter your secret key here.',
region: 'us-east-2'
);
const params =
Bucket: 'enter your bucket here.',
Key: folder + '/' + filename + ".jpg",
ACL: 'public-read',
ContentEncoding : 'base64,',
Body: new Buffer(file.replace(/^data:image\/\w+;base64,/, ""),'base64'),
ContentType: 'image/jpeg'
;
bucket.upload(params, function (err, data)
if (err)
console.log('There was an error uploading your file: ', err);
return false;
console.log('Successfully uploaded file.', data);
return true;
);
【讨论】:
【参考方案4】:作为另一种解决方案。我改用 Body: fs.createReadStream 修复了我的问题,它就像一个魅力。
const uploadFile = () =>
fs.readFile(filename, (err, data) =>
if (err) throw err;
const params =
Bucket: `$process.env.S3_Bucket/ProfilePics`, // pass your bucket name
Key: `$decoded.id-pic.$filetypeabbrv`, // file will be saved as testBucket/contacts.csv
Body: fs.createReadStream(req.file.path),
ContentType: filetype,
;
s3.upload(params, function (s3Err, data)
if (s3Err) throw s3Err;
console.log(`File uploaded successfully at $data.Location`);
);
);
;
【讨论】:
以上是关于使用 node.js 保存存储在 s3 上的图像?的主要内容,如果未能解决你的问题,请参考以下文章
从 url 下载文件并将其上传到 AWS S3 而不保存 - node.js
使用 Node JS 从 Amazon S3 私有存储桶中检索图像