我正在MEAN(MongoDB,Express,AngularJS,node.js)堆栈上构建一个应用程序,需要将图像文件上传到Amazon S3。我是按照以下方式做的:
首先,http get
被发送到我的API,它指定交互的“策略文档”并将其返回到AngularJS前端。该后端代码看起来像这样(填入变量):
exports.S3Signing = function(req, res) {
var bucket = "MY_BUCKET_NAME",
awsKey = "MY_AWS_KEY",
secret = "MY_SECRET",
fileName = req.params.userId,
expiration = new Date(new Date().getTime() + 1000 * 60 * 5).toISOString();
var policy = {
"expiration": expiration,
"conditions": [
{"bucket": bucket},
{"key": fileName},
{"acl": 'public-read'},
["starts-with", "$Content-Type", ""],
["content-length-range", 0, 524288000]
]};
policyBase64 = new Buffer(JSON.stringify(policy), 'utf8').toString('base64');
signature = crypto.createHmac('sha1', secret).update(policyBase64).digest('base64');
res.json({bucket: bucket, awsKey: awsKey, policy: policyBase64, signature: signature});
};
此过程的前端(AngularJS)代码如下所示:
$http.get('/api/v1/auth/signS3/' + userId).success(function(data, status) {
var formData = new FormData();
formData.append('key', userId);
formData.append('AWSAccessKeyId', data.awsKey);
formData.append('acl', 'public-read');
formData.append('policy', data.policy);
formData.append('signature', data.signature);
formData.append('Content-Type', image.type);
formData.append('file', image);
$http({
method: 'POST',
url: 'http://' + data.bucket + '.s3.amazonaws.com/',
headers: {'Content-Type': 'multipart/form-data'},
data: formData
}).success(function(data) {
deferred.resolve(data);
}).error(function(err) {
deferred.reject(err);
});
}).error(function(err, status) {
deferred.reject(err);
});
但是,就像目前一样,如果我发布图片,我会收到以下错误:
Malformed POST Request The body of your POST request is not well-formed multipart/form-data.
如果我将http POST调用更改为AngularJS,并删除“content-type”:“multipart / form-data”规范,如下所示:
$http.post('http://' + data.bucket + '.s3.amazonaws.com/', formData).success(function(data) {
deferred.resolve(data);
}).error(function(err) {
deferred.reject(err);
});
我收到了以下错误:
Precondition Failed At least one of the pre-conditions you specified did not hold Bucket POST must be of the enclosure-type multipart/form-data
我已经尝试过任何我能想到的条件和规格的组合。我在这里缺少什么?
答案 0 :(得分:1)
我认为问题在于我试图上传的“文件”的格式。我正在使用this AngularJS指令,并且它返回调整大小的图像的格式不是实际文件。我仍在使用相同的指令,但不再使用图像调整大小。
我更改了上传过程的结构,以完成node.js后端的大部分工作。 AngularJS函数如下所示:
uploadImage: function(image, userId) {
var deferred = $q.defer(),
formData = new FormData();
formData.append('image', image, image.name);
$http.post('/api/v1/user/' + userId + '/image', formData, {
transformRequest: angular.identity,
headers: { 'Content-Type': undefined }
}).success(function(data, status) {
deferred.resolve(data);
}).error(function(err, status) {
deferred.reject(err);
});
return deferred.promise;
}
发布的node.js / express端点如下所示:
exports.uploadImage = function(req, res) {
postToS3 = function(image, userId) {
var s3bucket = new AWS.S3({params: {Bucket: config.aws.bucket}}),
deferred = Q.defer(),
getExtension = function(filename) {
var i = filename.lastIndexOf('.');
return (i < 0) ? '' : filename.substr(i);
},
dataToPost = {
Bucket: config.aws.bucket,
Key: 'user_imgs/' + userId + getExtension(image.name),
ACL: 'public-read',
ContentType: image.type
};
fs.readFile(image.path, function(err, readFile) {
dataToPost.Body = readFile;
s3bucket.putObject(dataToPost, function(err, data) {
if (err) {
deferred.reject(err.message);
} else {
deferred.resolve(data);
}
});
});
return deferred.promise;
};
postToS3(req.files.image, req.params.userId).then(function(data) {
res.json(200, data);
}, function(err) {
res.send(500, err);
})
};
现在使用亚马逊的AWS sdk for node.js。
答案 1 :(得分:0)
最近我也遇到了同样的问题。您需要将dataURI
转换为Blob
并上传从此函数返回的文件。使用S3上传即可正常上传。
function dataURItoBlob(dataURI) {
// convert base64/URLEncoded data component to raw binary data held in a string
var byteString;
if (dataURI.split(',')[0].indexOf('base64') >= 0)
byteString = atob(dataURI.split(',')[1]);
else
byteString = unescape(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
// write the bytes of the string to a typed array
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ia], {type:mimeString});
}
答案 2 :(得分:0)
如果你只删除:
headers: {'Content-Type': 'multipart/form-data'},
对于图像,我刚刚发送了类似的内容:
$("#your_image_id").files[0]