2012-01-30 93 views
13

我使用curl調用Java ReST API來檢索URL。然後,Java使用我的S3憑證爲S3上傳生成一個預先簽名的URL,並在ReST回覆中返回。 Curl獲取URL並將其用於上傳到S3,但S3返回403「我們計算的請求籤名與您提供的簽名不匹配,請檢查您的密鑰和簽名方法。」使用預先簽名的URL通過curl上傳到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); 
    } 
} 

和捲曲,從慶典跑,我執行此:

echo Will try to upload chunk to ${location} 
curl -i -X POST \ 
     -F 'Content-Type=application/octet-stream' \ 
     -F "[email protected]${fileName}" \ 
     ${location} || (echo upload chunk failed. ; exit 1) 

除其他事項外,我試過PUT,而且我嘗試過「Content-type」(小寫字母T)。我意識到我錯過了某些東西(或某些東西)顯而易見,但是在閱讀了相應的文檔,使用Google搜索並查看了很多類似的問題後,我不確定這是什麼。我看到很多關於需要的標題的提示,但我認爲這個被拒絕的URL應該可以消除這些需求。也許不會?

TIA!

更新:

只是要清楚,我已經測試的下載,並且運行良好。

Java的樣子:

GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(BUCKET, key, HttpMethod.GET); 
req.setExpiration(expiration); 

和捲曲很簡單:

curl -i ${location} 

回答

15

我已經能夠產生通過C#預標識的URL,並上傳後通過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 
+0

感謝你。我堅持使用我的解決方案,因爲我首先得到它,但我將其標記爲正確,因爲它解決了原始查詢,並且,我認爲它更好。 – 2012-01-31 20:30:14

+8

對我而言,預先簽名的網址包含需要我用引號括住整個網址的字符。一旦我做到了,你的回答就完美了。 – 2014-03-17 21:52:07

+0

對我來說,使用POST預先簽名的URL不起作用。只切換方法(在GeneratePresignedUrlRequest和curl中)解決了這個問題。 – 2017-01-28 16:01:23

-1

儘管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,並且還意味着所有發佈的信息都必須單獨傳達給客戶,但它確實有效。

+0

有趣的,我不知道這(前?)限制 - 它已被刪除從這個主題的[當前文檔](http://docs.amazonwebservices.com/AmazonS3/2006-03-01/dev/RESTAuthentication.html#RESTAuthenticationQueryStringAuth),並且例如[PUT on S3:Problem](https://forums.aws.amazon.com/thread.jspa?messageID=262822񀊦)展示了使用'PUT'的一個顯然有用的例子(儘管在那裏討論了側面問題)。 – 2012-01-31 16:44:54

+0

我剛剛證實,使用PUT確實可以正常工作,正如預期的那樣,通過C#生成預簽名的URL,然後通過_curl_下載 - 我將在休息之後發佈更多細節作爲答案。 – 2012-01-31 18:29:42

+0

感謝您的跟進。 – 2012-01-31 20:28:25

4

當使用curl進行此操作時,您需要將url置於單引號中,否則會將半數查詢字符串切掉(帶有鍵/簽名的部分)。

0

生成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(); 
} 
+0

request.setContentType(「application/octet-stream」);有用!我之前得到了403個禁止錯誤。我想知道它爲什麼起作用 – Jason 2017-07-24 02:17:07

相關問題