我在将文件上传到Amazon S3时遇到问题。我开发了Grails RESTful服务,该服务使用AWS Java SDK生成预签名的URL。当客户端上传文件时,它首先检索预先签名的URL,然后使用它将文件直接上传到我的S3存储桶。所以我有一个Grails服务,它创建一个预先签名的URL,如此......
def generateFileUploadUrl(AmazonS3Client client, String bucketName, String key, int expiryMins) {
GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(bucketName, key);
req.setMethod(HttpMethod.POST);
req.setExpiration(getExpiration(expiryMins));
return client.generatePresignedUrl(req);
}
然后客户端检索具有以下格式的URL ...
https://{bucketname}.amazonaws.com/{key}?AWSAccessKeyId={accesskey}&Expires={expiry}&Signature={signature}
然后客户端使用Danial Farid的Angular File Upload module创建一个POST请求,如此...
Upload.upload({
url: destUrl, // url shown above
file: file
}).progress(function (evt) {
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
console.log('progress: ' + progressPercentage + '% ' + evt.config.file.name);
}).success(function (data, status, headers, config) {
console.log('file ' + config.file.name + 'uploaded. Response: ' + data);
}).error(function (data, status, headers, config) {
console.log('error status: ' + status);
});
起初我收到了有关CORS设置的错误,但在我的Bucket权限中编辑CORS origin配置后,我开始收到403禁止响应。 403响应中的消息是'我们计算的请求签名与您提供的签名不匹配。检查您的密钥和签名方法。'。提供的AWS Access Key和Signature匹配,因此我不确定确切的错误是什么。
我的请求是否缺少一些额外信息?查看了其他一些帖子,例如this,它们手动创建了一个与URL一起发送的策略文档,但它没有使用AWS Java SDK。
碰巧,我的方法适用于GET请求,我可以检索文档。只是无法上传。
答案 0 :(得分:1)
我知道这是一个古老的问题,但它似乎仍然相关,并且仍然看起来相当棘手。 S3签名的URL上传对于请求中使用的字段非常特别,响应和错误消息对您来说没有太大帮助 - 我认为这是出于安全原因的目的,但它确实使调试变得困难。 / p>
AWS签名流程也发生了变化 - 此时的版本(2016年3月)是AWS签名版本4(http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html)。在查看示例和Stackoverflow等时,您需要小心,这些信息与您使用的相同签名版本相关,因为它们不能很好地混合。
我开始使用AWS SDK进行角度/节点文件上传,但最终发现在没有SDK的情况下更容易在服务器(node.js)端生成策略。这里有一个很好的例子(尽管是节点,而不是基于Grails):https://github.com/danialfarid/ng-file-upload/wiki/Direct-S3-upload-and-Node-signing-example(但请注意这里的S3存储桶名称问题:AngularJs Image upload to S3)。
要注意的一件事是,您在策略生成中正确包含文件内容类型,并且此内容类型与您实际上传的文件的内容类型正确匹配。
作为参考,这是角侧的代码,对我有用:
$scope.upload = function (file) {
console.log("WebUploadCtrl upload");
console.log("WebUploadCtrl sending S3sign request");
var query = {
filename: file.name,
type: file.type
};
$http.post('/api/s3sign', query).success(function(response) {
console.log("WebUploadCtrl s3sign response received");
var s3ResponseParams = response;
console.log("WebUploadCtrl upload AWSAccessKeyId: " + response.AWSAccessKeyId);
console.log("WebUploadCtrl upload signature: " + response.Signature);
$scope.upload = Upload.upload({
url: s3ResponseParams.url, //s3Url
transformRequest: function(data, headersGetter) {
var headers = headersGetter();
delete headers.Authorization;
return data;
},
fields: s3ResponseParams.fields, //credentials
method: 'POST',
file: file
}).progress(function(evt) {
$scope.progressPerCent = parseInt(100.0 * evt.loaded / evt.total);
console.log('progress: ' + $scope.progressPerCent);
}).success(function(data, status, headers, config) {
// file is uploaded successfully
console.log('file ' + config.file.name + 'is uploaded successfully. Response: ' + data);
}).error(function() {
// Some error has occured
console.log('Error uploading to S3');
});
});
};