![](/img/trans.png)
[英]AWS S3 Java Access Denied Service: Amazon S3; Status Code: 403; Error Code: AccessDenied;
[英]Android HttpURLConnection PUT to Amazon AWS S3 403 error
使用以下代码使用具有签名,到期和访问密钥的预签名URL将文件上传到Amazon S3,我可以使用普通的Java代码上传文件,但是Android中的相同代码给我403错误。 使用Amazon SDK生成预签名URL
我已阅读http://developer.android.com/reference/java/net/HttpURLConnection.html和http://android-developers.blogspot.com/2011/09/androids-http-clients.html,但无法弄清楚我应该使用什么标头参数,我猜在android中它正在请求中设置标头,哪个服务器拒绝
HttpURLConnection connection=(HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("PUT");
OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());
out.write("This text uploaded as object.");
out.close();
int responseCode = connection.getResponseCode();
例外:403; 签名不匹配:-o
有人遇到过这个问题吗? 还是在Android库的幕后添加了Header参数的更多详细信息?
请像这样设置您的内容类型:
connection.setRequestProperty("Content-Type"," ");
因为HttpsUrlConnection的默认值自动将内容类型生成为:
"Content-Type: application/x-www-form-urlencoded"
这将导致签名不匹配。
因此,经过一些试验/错误/搜索后发现了问题所在:
创建预签名URL时,重要的是要指定Content-Type(基于您的数据),否则您将继续获得403 Signature不匹配,则在HttpURLConnection连接对象中应提及您在此处指定的contentType
string s3url = s3Client.GetPreSignedURL(new GetPreSignedUrlRequest()
.WithBucketName(bucketName)
.WithKey(keyName)
.WithContentType("application/octet-stream") // IMPORTANT
.WithVerb(HttpVerb.PUT)
.WithExpires(<YOUR EXPIRATION TIME>);
在您的连接内部..(“ PUT”)之后添加到有问题的代码中
connection.setFixedLengthStreamingMode(< YOUR DATA.LENGTH ?>);
connection.setRequestProperty("Content-Type","application/octet-stream");
检查此错误 ,最新的SDK应该允许您设置Content-Type
生成URL的方式:
private static URL generateRUL(String objectKey, String ACCESS_KEY, String SECRET_KEY, String BUCKET_NAME) {
AmazonS3 s3Client = new AmazonS3Client(new BasicAWSCredentials(ACCESS_KEY, SECRET_KEY));
URL url = null;
try {
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(BUCKET_NAME, objectKey);
request.setMethod(com.amazonaws.HttpMethod.PUT);
request.setExpiration(new Date( System.currentTimeMillis() + (60 * 60 * 1000)));
// Very important ! It won't work without adding this!
// And request.addRequestParameter("Content-Type", "application/octet-stream") won't work neither
request.setContentType("application/octet-stream");
url = s3Client.generatePresignedUrl(request );
} catch (AmazonServiceException exception) {
} catch (AmazonClientException ace) { }
return url;
}
上传文件的方式:
public int upload(byte[] fileBytes, URL url) {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("PUT");
connection.setRequestProperty("Content-Type", "application/octet-stream"); // Very important ! It won't work without adding this!
OutputStream output = connection.getOutputStream();
InputStream input = new ByteArrayInputStream(fileBytes);
byte[] buffer = new byte[4096];
int length;
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
output.flush();
return connection.getResponseCode();
}
您是否在使用适用于Android的AWS开发工具包 ? 它具有正确的API,我怀疑使用该API可以更轻松地将其上传到S3,并且对此更安全。 我相信他们那里也有教程,代码示例和演示。
还有一个S3和您可能需要的其他类的API 。 PutObjectRequest可以帮助您从电话客户端上载文件,并且在您的情况下非常有用。
我有同样的问题。 这就是我遇到它的原因:
如果预签名URL的创建者有权访问该对象,则预签名URL可让您访问URL中标识的对象。 也就是说,如果您收到一个预签名URL来上载对象,则只有在预签名URL的创建者具有上载该对象的必要权限的情况下,您才能上载该对象 。
http://docs.aws.amazon.com/AmazonS3/latest/dev/PresignedUrlUploadObject.html
一旦我对s3存储桶授予了lambda函数PutObject权限,它就起作用了!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.