S3 putObject使用aws-sdk失败



这让我抓狂,如果有任何帮助,我们将不胜感激!

为了在S3中设置我的bucket,我遵循http://www.cheynewallace.com/uploading-to-s3-with-angularjs/

关于这篇文章,我做了以下"改进",用通配符扩展了政策,并赋予了更多的权利

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:DeleteObject",
"s3:DeleteObjectVersion",
"s3:GetObject",
"s3:GetObjectAcl",
"s3:GetObjectTorrent",
"s3:GetObjectVersion",
"s3:GetObjectVersionAcl",
"s3:GetObjectVersionTorrent",
"s3:PutObject",
"s3:PutObjectAcl",
"s3:PutObjectVersionAcl"
],
"Resource": [
"arn:aws:s3:::photos-eu/*"
]
}
]
}

并添加<ExposeHeader>ETag<ExposeHeader>到bucket 的Cors设置

然后我使用aws-sdk的角度服务看起来像

/// <reference path="../../../typings/tsd.d.ts" />
module Services {
export interface IS3UploadService {
upload(imgName:string, imgData:string):ng.IPromise<{}>;
}
export class S3UploadService implements IS3UploadService {
static $inject = ['$q'];
private bucket:AWS.S3;
constructor(private $q:ng.IQService) {
var credentials = new AWS.Credentials("myAccessKeyId", "mySecretAccessKey");
AWS.config.update(credentials);
AWS.config.region = "eu-west-1";
this.bucket = new AWS.S3({params: {Bucket: 'peterparker-photos-eu', maxRetries: 10, region: "eu-west-1"}});
}
upload(imgName:string, imgData:string):ng.IPromise<{}> {
var deferred = this.$q.defer();
var params:AWS.s3.PutObjectRequest = {
Bucket: "peterparker-photos-eu",
Key: imgName,
Body: imgData,
ContentType: "image/jpeg",
ContentEncoding: "Base64"
};
this.bucket.putObject(params, (err:any, data:any) => {
if (err) {
console.error("->" + JSON.stringify(err));
deferred.reject(err);
} else {
console.info(data);
deferred.resolve(data);
}
});
return deferred.promise;
}
}
}
angular.module('App')
.service('S3UploadService', Services.S3UploadService);

出于测试目的,我在imgData中推送了一个编码为Base64的img,类似于"/9j/4AAQSkZJRgABAgAAZABkA……"(当然是一个用http://base64-image.de)

结果,每次我尝试,我都会得到以下错误

{"行":25,"列":24996,"源URL":http://localhost:8100/lib/aws-sdk/dist/aws sdk.min.js","message":"我们计算的请求签名与您提供的签名不匹配。检查您的密钥和签名方法。","code":"SignatureDoesNotMatch","region":null,"time":"2016-06-08T15:12:0.9945Z","requestId":null"statusCode":403,"retryable":false,"retaryDelay":60.59883770067245}

太有趣了。。。

更新标题:

General
Request URL:https://peterparker-photos-eu.s3-eu-west-1.amazonaws.com/1465408512724.jpg
Request Method:PUT
Status Code:403 Forbidden
Remote Address:54.231.131.16:443
Response headers
Access-Control-Allow-Methods:HEAD, GET, PUT, POST, DELETE
Access-Control-Allow-Origin:*
Access-Control-Expose-Headers:ETag, x-amz-meta-custom-header
Connection:close
Content-Type:application/xml
Date:Wed, 08 Jun 2016 17:55:20 GMT
Server:AmazonS3
Transfer-Encoding:chunked
Vary:Origin, Access-Control-Request-Headers, Access-Control-Request-        Method
x-amz-id-...
x-amz-request-id:...
Request Headers
Accept:*/*
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4,de;q=0.2
Authorization:AWS ...
Connection:keep-alive
Content-Encoding:Base64
Content-Length:38780
Content-MD5:...
Content-Type:image/jpeg; charset=UTF-8
Host:peterparker-photos-eu.s3-eu-west-1.amazonaws.com
Origin:http://localhost:8100
Referer:http://localhost:8100/?ionicplatform=ios
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5)             AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36
X-Amz-Date:Wed, 08 Jun 2016 17:55:20 GMT
X-Amz-User-Agent:aws-sdk-js/2.3.18
Request payload
Img base64 code

更新

即使尝试上传非Base64内容,也会出现相同的错误

var paramsHtml:AWS.s3.PutObjectRequest = {
Bucket: "peterparker-photos-eu",
Key: "HelloWorld.html",
Body: "The Body",
ContentType: "text/html"
};

更新#2

我转到了一个由我的nodejs服务器生成的签名URL的解决方案,如下面的解决方案所述,但仍然得到了相同的错误。。。但我至少尝试过;)

使用签名的url 将文件从angularjs直接上传到amazons3

Freak我终于找到了解决方案,或者至少找到了一个解决方案。

在将我的客户端基于aws-sdk的解决方案迁移到服务器生成签名URL的解决方案后,我仍然面临同样的错误。长话短说,它通过在两侧设置标题的内容类型来解决问题。

如果有人有一天遇到同样的问题,我的代码:

服务器Node.js

var AWS = require('aws-sdk');
AWS.config.update({accessKeyId: "myKey", secretAccessKey: "mySecret"});
AWS.config.region = 'eu-west-1';
app.post('/api/images', securityPolicy.authorise, function (req, res) {
var s3 = new AWS.S3();
var imgName = req.body.imgName;
var contentType = req.body.contentType;
// Expires in seconds
var params = {Bucket: 'photos-eu', Key: imgName, Expires: 600, ContentType: contentType};
s3.getSignedUrl('putObject', params, function (err, url) {
if (err) {
res.status(500).json({
error: "Presigned S3 url for putObject can't be created. " + JSON.stringify(err)
});
} else {
res.json({url: url});
}
});
});

客户端角度:

  • 首先或者当然有调用节点服务器的部分,对我的服务器进行POST

然后第二部分处理签名的URL

private uploadToS3(preSignedUrl:string, imgData:string):ng.IPromise<{}> {
var deferred = this.$q.defer();
// Post image to S3
this.$http({
method: 'PUT',
url: preSignedUrl,
headers: {'Content-Type': 'image/jpeg'},
data: imgData
})
.then((response:any) => {
console.log("Image uploaded to S3" + JSON.stringify(response));
deferred.resolve();
}, (response:any) => {
console.log("Error Presigned URL" + JSON.stringify(response));
deferred.reject(response);
});
return deferred.promise;
}

最新更新