0

我想創建一個簽名的URL,並從我的電腦上傳文件到谷歌雲存儲使用它。無法成功上傳文件使用簽名的URL到谷歌雲存儲從高級REST客戶端

我正在使用高級REST客戶端(ARC)作爲客戶端應用程序。在服務器端,我有一個在Appengine上運行的基於球衣的服務器。

我首先從ARC發送一個GET請求,接收哪個app引擎生成一個簽名的URL並將它返回給響應。

之後,我做了一個PUT請求,我要在正文中上傳文件,請求URL設置爲在GET響應中收到的內容。

的代碼片斷創建簽署網址:

 String encodedUrl = null; 
     String contentMD5 = ""; 
     String contentType = ""; 
     String httpVerb; 


     httpVerb = "PUT"; 

     Calendar calendar = Calendar.getInstance(); 
     calendar.add(Calendar.MINUTE, 10); 
     long expiration = calendar.getTimeInMillis()/1000L; 

     String canonicalizedResource = "/" + bucketName + "/" + objectName; 
     String baseURL = "https://storage.googleapis.com" + canonicalizedResource; 

     String stringToSign = 
       httpVerb + "\n" + contentMD5 + "\n" + contentType + "\n" + expiration + "\n" 
         + canonicalizedResource; 

     AppIdentityService service = AppIdentityServiceFactory.getAppIdentityService(); 
     String googleAccessId = service.getServiceAccountName(); 

     SigningResult signingResult = service.signForApp(stringToSign.getBytes()); 
     String encodedSignature = null; 
     try { 
      encodedSignature = 
        new String(Base64.encodeBase64(signingResult.getSignature(), false), "UTF-8"); 
     } catch (UnsupportedEncodingException e) { 
      throw new InternalServerErrorException(); 
     } 

     String signature = null; 
     try { 
      signature = URLEncoder.encode(encodedSignature, "UTF-8").toString(); 
     } catch (UnsupportedEncodingException e) { 
      throw new InternalServerErrorException(); 
     } 

     encodedUrl = 
       baseURL + "?GoogleAccessId=" + googleAccessId + "&Expires=" + expiration 
         + "&Signature=" + signature; 
     System.out.println("Signed URL is: "+encodedUrl); 

但是我觀察了以下問題:

  1. 每當我發送任何文件類型的PUT請求,我得到以下錯誤:

    錯誤 - 403
    碼 - SignatureDoesNotMatch

    消息 - 我們計算的請求籤名與您提供的簽名不匹配。檢查您的Google祕密密鑰和簽名方法

請注意,在我的代碼中,我在創建要簽名的字符串時將內容類型設置爲「」。同時創建PUT請求時,我不包含任何Content-type標頭。

據我所知,如果我在創建簽名URL時不在stringToSign中包含contentType,並且在發送PUT請求時沒有將其作爲頭添加,它應該沒問題。那麼錯誤的原因是什麼?

  1. 之後,我通過代碼進行了更改,並在代碼中創建stringToSign時添加了contentType,並在發送PUT請求時給出了相應的Content-Type頭。

在這種情況下,我可以上傳文件,但上傳的文件被修改/損壞。我嘗試使用text/plain和image/jpeg。

的問題是,下面的文字是在文件的開頭說:

------WebKitFormBoundaryZX8rPPhnm1WXPrUf 
Content-Disposition: form-data; name="fileUpload5"; filename="blob" 
Content-Type: text/plain 

我可以在文本文件,並在十六進制編輯器打開.jpg文件看到這一點。 .jpg在標準圖像應用程序中無法打開,因爲文件已被開頭的文本損壞

我在這裏丟失了什麼嗎?這是高級REST客戶端中的任何問題嗎? 實際上,無論何時我發送PUT請求與正文中的某個文件,我都會在ARC中收到一條消息: 內容類型標題將在發送請求時最終更改爲multipart/form-data 但是,我保存將所有消息導出到ARC的文件中,但沒有發現任何Content-type頭部設置爲multipart/form-data的消息。 那麼爲什麼這個消息來了,它實際上是一個問題?

回答

1

網址簽名的代碼是棘手和非常難以調試。幸運的是,谷歌的谷歌雲庫有一個signUrl函數爲您處理這件事。我強烈建議你使用它,而不是自己重寫它。 Here's the documentation。現在

,如果你想自己調試它,檢查錯誤消息是超級有用。它將包括服務器檢查簽名的字符串的完整副本。打印出你的stringToSign變量,看看它有什麼不同。那會告訴你什麼是錯的。

現在,您的具體問題:它聽起來像你生成一個可以接受已簽署的網址,但後來您的客戶嘗試就好像它是做多,形式上傳上傳到GCS。您正在查看的文本是HTTP多部分請求的一部分,「multipart/form-data」警告也指出了該方向。看看您使用的應用程序是否有某種您可能意外使用的「表單」模式/選項?

+1

謝謝。正如您所提到的那樣,高級REST客戶端似乎存在一些問題,因爲即使指定了其他內容類型,它也會將上載作爲多部分表單數據進行上傳。我找不到如何更改設置,但我現在使用curl命令行工具進行上傳/下載,並且工作正常。 –

相關問題