4

使用BlobStore的createUploadURL函數上傳到GCS(Google雲端存儲)時,我可以提供回調以及將發送到回調URL的標頭數據。在Google Cloud Storage簽署的URL中提供回調URL

似乎沒有成爲一個辦法做到這一點與GCS的signed URL's

我知道有Object Change Notification但將不允許用戶提供在後的頭上傳的具體信息,該方法它可能與createUploadURL的回調。

我的感覺是,如果createUploadURL可以做到這一點,就必須有辦法用簽名的URL來完成它,但我找不到任何文檔。我想知道是否有人可能知道createUploadURL如何實現回調調用行爲。


PS:我試圖搬開從createUploadURL因爲__BlobInfo__實體它創造,這對於我的具體使用情況下,我並不需要的,並以某種方式似乎是不可磨滅的,並且浪費存儲空間。


更新:它的工作!這裏是如何:

答案很簡單:它不能與PUT來完成,但可以用POST

長的答案來完成:

如果你看一下signed-URL頁,前面HTTP_Verb,在下描述,有一個微妙的說明,這個頁面只與GET,HEAD,PUT和DELETE有關,但是POST是一個完全不同的遊戲。我錯過了這一點,但事實證明這非常重要。

有一整頁HTTP Headers沒有列出可以與POST一起使用的重要頭文件;那頭是success_action_redirect,正如voscausa正確回答。

在POST頁谷歌「強烈建議」使用PUT,除非處理表單數據。但是,POST有一些PUT沒有的好功能。他們可能擔心POST會給我們提供太多的字符串來纏住自己。

但我想說這是完全值得的createUploadURL,並編寫自己的代碼重定向到回調。這裏是如何:


代碼:

如果您在Python voscausa的code正在努力是非常有幫助的。

我使用apejs在Java應用程序編寫的JavaScript,所以我的代碼如下所示:

  var exp = new Date() 
      exp.setTime(exp.getTime() + 1000 * 60 * 100); //100 minutes 

      json['GoogleAccessId'] = String(appIdentity.getServiceAccountName()) 
      json['key'] = keyGenerator() 
      json['bucket'] = bucket 
      json['Expires'] = exp.toISOString(); 
      json['success_action_redirect'] = "https://" + request.getServerName() + "/test2/"; 
      json['uri'] = 'https://' + bucket + '.storage.googleapis.com/'; 

      var policy = {'expiration': json.Expires 
         , 'conditions': [ 
          ["starts-with", "$key", json.key], 
          {'Expires': json.Expires}, 
          {'bucket': json.bucket}, 
          {"success_action_redirect": json.success_action_redirect} 
          ] 
         }; 

      var plain = StringToBytes(JSON.stringify(policy)) 
      json['policy'] = String(Base64.encodeBase64String(plain)) 
      var result = appIdentity.signForApp(Base64.encodeBase64(plain, false)); 
      json['signature'] = String(Base64.encodeBase64String(result.getSignature())) 

上面的代碼首先提供相關的字段。 然後創建一個策略對象。然後它將對象串化並將其轉換爲一個字節數組(您可以在Java中使用.getBytes,我必須爲javascript編寫函數)。 編碼此數組的版本一個base64,填充政策字段。 然後它使用appidentity包進行簽名。最後簽名是base64編碼的,我們完成了。

在客戶端,json對象的所有成員都將被添加到窗體中,除了窗體的地址uri

 var formData = new FormData(document.forms.namedItem('upload')); 
     var blob = new Blob([thedata], {type: 'application/json'}) 
     var keys = ['GoogleAccessId', 'key', 'bucket', 'Expires', 'success_action_redirect', 'policy', 'signature'] 
     for(field in keys) 
      formData.append(keys[field], url[keys[field]]) 
     formData.append('file', blob) 
     var rest = new XMLHttpRequest(); 
     rest.open('POST', url.uri) 
     rest.onload = callback_function 
     rest.send(formData) 

如果您沒有提供重定向,則成功的響應狀態將爲204。但是,如果你重定向,狀態將是200.如果你得到了403或400個關於簽名或策略的內容可能是錯誤的。看看responseText。如果通常有幫助。


有幾件事情需要注意:

  • POST和PUT有一個簽名字段,但這些意味着略有不同的事情。在POST的情況下,這是政策的簽名。
  • PUT有一個包含密鑰(對象名稱)的基地址,但用於POST的URL可能只包含存儲區名稱
  • PUT要求從UNIX時期開始秒數過期,但POST要求它作爲ISO字符串。
  • 認沽簽名應該URL編碼(Java語言:用URLEncoder.encode調用其包裝)。但對於POST,Base64編碼就足夠了。
  • 通過擴展,POST對Base64.encodeBase64String(result.getSignature())進行擴展,並且不使用Base64.encodeBase64URLSafeString函數
  • 您不能通過POST傳遞額外的頭文件;只允許在POST page中列出的那些。
  • 如果您提供success_action_redirect一個URL,它會收到與一個GET,ETAG
  • 使用POST的另一個好處是您可以提供大小限制。然而,使用PUT時,如果文件違反了您的大小限制,則只能在完全上傳後將其刪除,即使它是多個千兆字節。

有什麼不對createUploadURL?

以上方法是手動createUploadURL。 但是:

  • 你沒有得到它創造了許多指標,是不可磨滅的那些__BlobInfo__對象。這讓我惱火,因爲它浪費了大量的空間(這讓我想起一個單獨的問題:issue 4231請去給它一個明星)
  • 您可以提供自己的對象的名稱,這有助於你的水桶創建文件夾。
  • 您可以爲每個鏈接提供不同的到期日期。

對於非常非常少數的JavaScript應用程序,工程師:

function StringToBytes(sz) { 
    map = function(x) {return x.charCodeAt(0)} 
    return sz.split('').map(map) 
} 
+0

還有一點讓我感到困惑的是,使用_createUploadUrl_時,可以在POST表單中提供自定義字段,但不能像POST api那樣提供自定義字段。 我試過使用python的_base64.urlsafe_b64decode_函數來查看是否可以從_createUploadUrl_的輸出中做出任何意義,但不幸的是輸出結果不是字符串。 – user2782503

回答

2

當您使用GCS post對象時,您可以在策略文檔中包含succes_action_redirect。

文檔這裏:文檔:
Python示例這裏:https://github.com/voscausa/appengine-gcs-upload

例回調結果:

def ok(self): 
    """ GCS upload success callback """ 

    logging.debug('GCS upload result : %s' % self.request.query_string) 
    bucket = self.request.get('bucket', default_value='') 
    key = self.request.get('key', default_value='') 
    key_parts = key.rsplit('/', 1) 
    folder = key_parts[0] if len(key_parts) > 1 else None 
+0

任何Java示例? – Micro

0

您可以在已簽署的網址如下標題:

HTTP Headers and Query String Parameters

見,例如,我如何請求在訪問簽名的URL時返回特定的Content-Disposition標頭:

public static String getSignedUrl(String httpVerb, String fileName, String gsKey) { 
    try { 
     long expiration = new Date().getTime()/1000 + 5 * 60 * 60; 
     String unsigned = stringToSign(expiration, gsKey, httpVerb); 
     String signature = sign(unsigned); 
     return new StringBuilder(BASE_URL).append("/") 
       .append(BUCKET) 
       .append("/") 
       .append(gsKey) 
       .append("?GoogleAccessId=") 
       .append(identityService.getServiceAccountName()) 
       .append("&Expires=") 
       .append(expiration) 
       .append("&response-content-disposition=") 
       .append(URLEncoder.encode("attachment;filename=" + "\"" + fileName + "\"", "UTF-8")) 
       .append("&Signature=") 
       .append(URLEncoder.encode(signature, "UTF-8")).toString(); 
    } catch (UnsupportedEncodingException e) { 
     e.printStackTrace(); 
    } 
    return null; 
} 

我希望它有幫助 - 我想看看你如何從createUploadUrl移開。

0

我使用的溶液是打開Object Changed Notifications。任何時候添加一個對象時,Post都會發送到一個URL - 在我的情況下 - 我的項目中的一個servlet。

doPost()我收到所有加入到GCS的反對信息,從那裏我可以做任何事情。

這在我的App Engine項目中效果很好。

相關問題