从AngularJS发布到Amazon S3时发生错误

我在MEAN(MongoDB,Express,AngularJS,node.js)堆栈上构build一个应用程序,需要将图像file upload到Amazon S3。 我正在以如下方式进行:

首先,http get被发送到我的API,它指定交互的“策略文档”并将其返回给AngularJS前端。 后端代码如下所示(填充variables):

 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 

我已经尝试了任何我能想到的条件和规范的组合。 我在这里错过了什么?

我相信问题是我试图上传的“文件”的格式。 我正在使用这个 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); }) }; 

这现在正在使用Amazon的AWS sdk for node.js。

最近我也面临同样的问题。 您需要将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}); } 

应该工作,如果你只是删除:

 headers: {'Content-Type': 'multipart/form-data'}, 

和我刚刚发送像这样的图像:

 $("#your_image_id").files[0]