更新资料
我有个 坏
消息。根据http://aws.amazon.com/releasenotes/1473534964062833上SDK
2.1.6的发行说明:
"The SDK will now throw an error if ContentLength is passed into an Amazon S3 presigned URL (AWS.S3.getSignedUrl()). Passing a ContentLength is not supported by the SDK, since it is not enforced on S3's side given the way the SDK is currently generating these URLs. See GitHub issue #457."
我发现有些情况下必须包含ContentLength(特别是如果您的客户端通过了ContentLength,以便签名会匹配),然后在其他情况下,如果您包含带有参数错误的ContentLength,则getSignedUrl会抱怨:“预签名网址中不支持contentlength
”。我注意到当我更改进行呼叫的机器时,行为将会改变。大概是另一台机器连接到服务器场中的另一台Amazon服务器。
我只能猜测为什么在某些情况下会出现这种行为,而在另一些情况下则不会。也许不是所有的Amazon服务器都已完全升级?无论哪种情况,为处理此问题,我现在都尝试使用ContentLength,如果它给我参数错误,则在没有它的情况下再次调用getSignedUrl。这是解决此SDK奇怪行为的方法。
一个小例子…看起来不是很漂亮,但是您可以理解:
MediaBucketManager.getPutSignedUrl = function ( params, next ) { var _self = this; _self._s3.getSignedUrl('putObject', params, function ( error, data ) { if (error) { console.log("An error occurred retrieving a signed url for putObject", error); // TODO: build contextual error if (error.pre == "UnexpectedParameter" && error.message.search("ContentLength") > -1) { if (params.ContentLength) delete params.ContentLength MediaBucketManager.getPutSignedUrl(bucket, key, expires, params, function ( error, data ) { if (error) { console.log("An error occurred retrieving a signed url for putObject", error); } else { console.log("Retrieved a signed url for putObject:", data); return next(null, data) } }); } else { return next(error); } } else { console.log("Retrieved a signed url for putObject:", data); return next(null, data); } });};因此,以下内容并不完全正确(在某些情况下会是正确的,但在其他情况下会给您参数错误),但可能会帮助您入门。
旧答案
似乎(对于将签名文件PUT到S3的文件,其中只有公开读取的ACL),当向P3提出请求时,将比较一些头。将它们与传递给getSignedUrl的内容进行比较:
CacheControl: 'STRING_VALUE',ContentDisposition: 'STRING_VALUE',ContentEncoding: 'STRING_VALUE',ContentLanguage: 'STRING_VALUE',ContentLength: 0,ContentMD5: 'STRING_VALUE',ContentType: 'STRING_VALUE',Expires: new Date || 'Wed De...'
请在此处查看完整列表:http :
//docs.aws.amazon.com/AWSJavascriptSDK/latest/AWS/S3.html#putObject-
property
调用getSignedUrl时,您将传递一个“参数”对象(在文档中已经很清楚了),该对象包含Bucket,Key和Expires数据。这是一个(NodeJS)示例:
var params = { Bucket:bucket, Key:key, Expires:expires };s3.getSignedUrl('putObject', params, function ( error, data ) { if (error) { // handle error } else { // handle data }});不太清楚的是将ACL设置为“公开读取”:
var params = { Bucket:bucket, Key:key, Expires:expires, ACL:'public-read' };非常模糊的是传递标头的概念,您希望客户端使用带签名的url将其与PUT操作一起传递给S3:
var params = { Bucket:bucket, Key:key, Expires:expires, ACL:'public-read', ContentType:'image/png', ContentLength:7469};在上面的示例中,我包含了ContentType和ContentLength,因为在javascript中使用XmlHTTPRequest时包括了这两个标头,并且在Content-
Length的情况下无法更改。我怀疑对于HTTP请求的其他实现(例如Curl等)会是这种情况,因为在提交包含(数据)主体的HTTP请求时,它们是必需的标头。
如果客户端在请求一个signedUrl时不包括有关文件的ContentType和ContentLength数据,则在将文件放置到S3(带有那个signedUrl)时,S3服务将找到客户端请求中包含的标头(因为它们是必需的标头),但签名将不包含它们-
因此,它们将不匹配,操作将失败。
因此,在进行getSignedUrl调用之前,您似乎必须知道要PUT到S3的文件的内容类型和内容长度。这对我来说不是问题,因为我公开了REST端点,以允许我们的客户端在对S3进行PUT操作之前就可以请求签名的url。由于客户端可以访问要提交的文件(此时他们已经准备好提交),因此客户端访问文件大小和类型并从我的端点请求带有该数据的签名URL是一项微不足道的操作。



