[英]Upload to s3 with curl using pre-signed URL (getting 403)
我正在使用curl調用Java ReST API來檢索URL。 然后,Java使用我的S3憑據生成用於S3上載的預簽名URL,並在ReST回復中返回該URL。 Curl獲取URL並使用它上傳到S3,但S3返回403“我們計算的請求簽名與您提供的簽名不匹配。請檢查您的密鑰和簽名方法。”
這是我用來生成預簽名URL的代碼:
public class S3Util {
static final AmazonS3 s3 = new AmazonS3Client( new AWSCredentials() {
@Override
public String getAWSAccessKeyId() {
return "XXXXXXX";
}
@Override
public String getAWSSecretKey() {
return "XXXXXXXXXXXXXX";
}
});
static final String BUCKET = "XXXXXXXXXXXXXXXXXXXXXXXXXXX";
static public URL getMediaChunkURL( MediaChunk mc, HttpMethod method ) {
String key = ...
//way in the future (for testing)...
Date expiration = new Date( System.currentTimeMillis() + CalendarUtil.ONE_MINUTE_IN_MILLISECONDS*60*1000 );
GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(BUCKET, key, method);
req.setExpiration(expiration);
req.addRequestParameter("Content-Type", "application/octet-stream");
//this gets passed to the end user:
return s3.generatePresignedUrl(req);
}
}
在curl中,從bash運行,我執行這個:
echo Will try to upload chunk to ${location}
curl -i -X POST \
-F 'Content-Type=application/octet-stream' \
-F "file=@${fileName}" \
${location} || (echo upload chunk failed. ; exit 1 )
除此之外,我嘗試了PUT,我嘗試過“內容類型”(小寫T)。 我意識到我錯過了一些顯而易見的東西(或者某些東西),但在閱讀了相應的文檔,谷歌搜索並查看了許多類似的問題后,我不確定那是什么。 我看到很多關於必需標題的提示,但我認為重新簽名的URL應該可以消除這些需求。 也許不吧?
TIA!
更新:
為了清楚起見,我測試了下載,這很好。
Java看起來像:
GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(BUCKET, key, HttpMethod.GET);
req.setExpiration(expiration);
和卷曲簡單地說:
curl -i ${location}
我已經能夠通過C#生成預先簽名的URL,然后按預期通過curl上傳。 鑒於我的測試我懷疑你確實沒有正確使用curl - 我已經能夠上傳一個這樣的文件:
curl -v --upload-file ${fileName} ${location}
參數-v
轉儲請求和響應頭(以及SSL握手)以進行調試和說明:
> PUT [...] HTTP/1.1
> User-Agent: curl/7.21.0 [...]
> Host: [...]
> Accept: */*
> Content-Length: 12
> Expect: 100-continue
請注意, - --upload-file
(或-T
)可以按預期方式促進PUT
,但會根據需要添加更多標頭,從而產生適當的響應:
< HTTP/1.1 100 Continue
< HTTP/1.1 200 OK
< x-amz-id-2: [...]
< x-amz-request-id: [...]
< Date: Tue, 31 Jan 2012 18:34:56 GMT
< ETag: "253801c0d260f076b0d5db5b62c54824"
< Content-Length: 0
< Server: AmazonS3
當使用curl執行此操作時,您需要將url放在單引號中,否則查詢字符串的一半會被切斷(帶有鍵/簽名的部分)。
生成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();
}
盡管GeneratePresignedUrlRequest
接受了一個http方法參數(並且有一個setMethod
函數),但除了GET之外,它似乎無法使用。
http://wiki.nercomp.org/wiki/images/0/05/AmazonWebServices.pdf聲明“簽署請求並將其提供給第三方執行的做法僅適用於簡單的對象GET請求。” 也許設置另一種方法可以用於某些東西,但顯然不是這個。
所以,相反,我必須按照這里的說明:
http://aws.amazon.com/articles/1434?_encoding=UTF8&jiveRedirect=1
這更復雜,因為客戶端需要發布完整的表單,而不僅僅是使用URL,並且還意味着所有帖子信息必須單獨傳遞給客戶端,但它似乎確實有效。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.