物件變更通知


當物件更新或新增至值區時,可使用物件變更通知來通知應用程式。

請注意,此功能不同於 Cloud Storage 的 Cloud Pub/Sub 通知。建議使用 Cloud Pub/Sub 通知來追蹤 Cloud Storage 值區中的物件變更,因為這種方式更快速、更靈活、更容易設定,也更符合成本效益。

物件變更通知的運作方式

用戶端應用程式可以傳送要求,監控特定值區中的物件變更。

完成監控要求會建立新的「通知管道」。通知訊息會透過通知管道傳送至監控值區的應用程式。目前只支援網路掛鉤這種通知管道類型。

啟動通知管道後,每當值區中新增、更新或移除物件,Cloud Storage 就會通知應用程式。例如,當您在值區中新增圖片時,即會通知應用程式建立縮圖。

下圖顯示處理變更通知的應用程式資料流範例。凡是可以接收 HTTPS POST 要求的應用程式伺服器均可用來處理變更通知。

物件變更通知元件
物件變更通知元件

物件變更通知的詳細資料

術語

下表說明物件變更通知說明文件中使用的幾個字詞:

字詞 說明
應用程式網址 應用程式的網址。這是傳送通知的位址。請注意,此位址必須是 HTTPS 網址;不允許使用 HTTP 網址。
管道 ID 通知管道的 ID。此 ID 在特定值區中不得重複,亦即如果單一值區有多個通知管道,則每個通知管道必須有不同的管道 ID。這個 ID 將與每則通知訊息一起傳送給應用程式。
資源 ID 受監控資源的不易解讀 ID。停止通知管道需要使用資源 ID。您可以從監控要求的回應或從通知事件訊息的 X-Goog-Resource-Id 標頭中擷取這個 ID。
用戶端憑證 (選用) 用戶端憑證可用來驗證通知事件。如要執行驗證,請透過您的監控要求設定自訂用戶端憑證。通知訊息將包含此憑證,以便您驗證訊息是否可信。

監控值區

如要開始監控值區中的變更通知事件,您可以使用 gsutil notification watchbucket 指令:

gsutil notification watchbucket [-i ChannelId] [-t ClientToken] ApplicationUrl gs://BucketName

此指令將建立通知管道,將通知事件傳送至指定值區的指定應用程式網址。通知管道將包含自訂用戶端憑證和管道 ID (如果已指定)。

如要進一步瞭解此指令,請執行 gsutil help notification watchbucket 指令。

以下是 gsutil 為了監控值區而產生的 POST 要求範例:

POST /storage/v1/b/BucketName/o/watch?alt=json HTTP/1.1
Host: www.googleapis.com
Content-Length: 200
User-Agent: google-api-python-client/1.0
Content-Type: application/json
Authorization: Bearer oauth2_token

{
  "token": "ClientToken",
  "type": "web_hook",
  "id": "ChannelId",
  "address": "ApplicationUrl"
}

通知授權

監控值區時,系統會將正在建立的通知管道關聯到啟動 API 要求的應用程式所屬的 Google Cloud Platform 主控台專案。這意味著,舉例來說,如果使用者透過 OAuth2 流程授予已安裝的應用程式或網路應用程式存取權,則應用程式建立的通知管道將會與應用程式的專案產生關聯,而不是與要監控的值區所屬的專案產生關聯。

請遵循下列三個步驟,在物件變更通知情境中設定授權:

建立服務帳戶

因為服務帳戶與專案相關聯,所以使用服務帳戶監控值區將會在該服務帳戶的專案中建立通知管道。

您應使用現有的服務帳戶或建立新的服務帳戶,然後下載相關聯的私密金鑰

設定 gsutil 使用服務帳戶

如要設定 gsutil 使用服務帳戶,您可以使用 Google Cloud SDK 來新增服務帳戶做為含有憑證的帳戶,以使用包括物件變更通知在內的 Google Cloud Platform 資源。新增憑證後,所有後續 gsutil 指令都將使用該服務帳戶的憑證。

如要依據服務帳戶建立憑證:

  1. 請確定您有最新版本的 Cloud SDK。您可以執行下列指令以更新元件:
    gcloud components update
    
  2. 使用 gcloud auth activate-service-account 指令,並指定服務帳戶電子郵件地址和私密金鑰。
    gcloud auth activate-service-account service-account-email --key-file path/to/key.p12
    

    其中:

    • service-account-email 是服務帳戶電子郵件地址,如下所示:1234567890123-abcdefghijklmonpqrstuvwxz01234567@developer.gserviceaccount.com
    • path/to/key.p12 是您建立服務帳戶時系統提示您下載的金鑰。如果您遺失此金鑰,可以回到 Google Cloud Platform 主控台的「Credentials」(憑證) 頁面,然後產生新的金鑰。
  3. 確認服務帳戶是作用中且含有憑證的帳戶。
    $ gcloud auth list
    Credentialed accounts:
    - 1234567890123-abcdefghijklmonpqrstuvwxz01234567@developer.gserviceaccount.com (active)
    

    您應該會看到服務帳戶憑證旁顯示 active。現在,您執行的所有 gsutil 物件通知指令都會使用服務帳戶憑證。

識別要接收通知的網域

只有在通知網址是通知管道專案許可清單中的網域時,監控要求才會成功。

將網域加入許可清單:

  1. 透過 Search Console 驗證程序驗證您的網域擁有權。
  2. 在 GCP 主控台中前往「憑證」頁面的「網域驗證」分頁。

    前往「憑證」頁面

  3. 按一下 [新增網域]。
  4. 在「設定 webhook 通知」對話方塊中輸入要驗證的網域。

    設定 webhook 通知對話方塊

  5. 按一下 [新增網域]。

    如何排解網域驗證問題:

    • 您必須在 Search Console 中以 https:// 網址註冊網域,或使用網域名稱供應商驗證方法驗證網域。
    • 確認您是 GCP 主控台專案的擁有者或編輯者 (請參閱專案成員和權限)。此外,您也必須是網域的網站擁有者才能收到通知;如果不是,則請要求網域擁有者將您新增為已驗證擁有者 (請參閱新增或移除擁有者)。
    • 您可以使用網站管理員工具的 Google API Explorer 列出網域中的網站,看看網域的 siteUrl 屬性開頭是否為 https://

移除通知管道

如要停止通知管道,您可以使用 gsutil notification stopchannel 指令:

gsutil notification stopchannel ChannelId ResourceId

這會停止指定資源 ID 和管道 ID 配對的所有通知事件。同一資源的其他作用中管道不受影響。資源和管道 ID 會出現在監控要求的回應或在通知事件訊息的內文中。

如要進一步瞭解此指令,請執行 gsutil help notification stopchannel 指令。

以下是 gsutil 為了停止管道而產生的 POST 要求範例:

POST /storage/v1/channels/stop HTTP/1.1
Host: www.googleapis.com
Content-Length: 200
User-Agent: google-api-python-client/1.0
Content-Type: application/json
Authorization: Bearer oauth2_token

{
  "resourceId": "ResourceId",
  "id": "ChannelId"
}

通知事件訊息類型

同步處理

發出監控要求後,系統會在建立新的通知管道時傳送通知事件。收到同步處理事件後,該值區發生的所有後續變更都會傳送到該通道設定的應用程式網址。

通知會以 POST 要求傳送至設定的應用程式網址。要求不含任何主體。同步處理通知中繼資料會納入要求的標頭中。以下是「同步處理」通知要求的範例:

POST /ApplicationUrlPath
Accept: */*
Content-Type: application/json; charset="utf-8"
Content_Length: 0
Host: ApplicationUrlHost
X-Goog-Channel-Id: ChannelId
X-Goog-Channel-Token: ClientToken
X-Goog-Resource-Id: ResourceId
X-Goog-Resource-State: sync
X-Goog-Resource-Uri: https://www.googleapis.com/storage/v1/b/BucketName/o?alt=json
新增、更新或刪除物件

每當在值區中新增物件、修改現有物件的內容或中繼資料,或從值區中刪除物件時,即會傳送通知事件。

通知會以 POST 要求傳送至設定的應用程式網址。要求主體含有 JSON 編碼訊息,如下列通知要求所示:

POST /ApplicationUrlPath
Accept: */*
Content-Length: 1097
Content-Type: application/json; charset="utf-8"
Host: ApplicationUrlHost
X-Goog-Channel-Id: ChannelId
X-Goog-Channel-Token: ClientToken
X-Goog-Resource-Id: ResourceId
X-Goog-Resource-State: ResourceState
X-Goog-Resource-Uri: https://www.googleapis.com/storage/v1/b/BucketName/o?alt=json

{
 "kind": "storage#object",
 "id": "BucketName/ObjectName",
 "selfLink": "https://www.googleapis.com/storage/v1/b/BucketName/o/ObjectName",
 "name": "ObjectName",
 "bucket": "BucketName",
 "generation": "1367014943964000",
 "metageneration": "1",
 "contentType": "application/octet-stream",
 "updated": "2013-04-26T22:22:23.832Z",
 "size": "10",
 "md5Hash": "xHZY0QLVuYng2gnOQD90Yw==",
 "mediaLink": "https://www.googleapis.com/storage/v1/b/BucketName/o/ObjectName?generation=1367014943964000&alt=media",
 "owner": {
  "entity": "user-jane@gmail.com"
 },
 "crc32c": "C7+82w==",
 "etag": "COD2jMGv6bYCEAE="
}
其中「ResourceState」是:
  • exists - 表示物件新增或更新。
  • not_exists - 表示物件刪除。

而且,JSON 訊息內容含有目前的物件表示法,如物件資源說明所述。

穩定傳送

物件變更通知會嘗試以可靠的方式將通知傳送給應用程式。但請注意,通知可能會無限期延遲,無法保證及時性。因為應用程式不一定隨時可用,因此在傳送通知時請遵循下列規則:

  • 如果通知傳送嘗試失敗,則會進行額外的嘗試。額外傳送嘗試的間隔是由指數輪詢演算法決定,在初次失敗後的 30 秒開始重試。後續傳送嘗試的執行間隔會逐漸增加,最多間隔 90 分鐘。請注意,後續的重試間隔會稍微以隨機方式設定,所以不會按確切的指數值發生。達到 90 分鐘的重試間隔上限後,後續重試會繼續在 7 天內每隔 90 分鐘重試傳送。如果在這段時間內仍無法傳送通知,則會清除通知。
  • 如果在 20 秒後無法連結到應用程式,或應用程式回應含有下列其中一項 HTTP 回應碼,則通知傳送嘗試就會被視為失敗並重試:
    • 500 內部伺服器錯誤
    • 502 閘道錯誤
    • 503 服務無法使用
    • 504 閘道逾時
  • 如果應用程式回應含有下列其中一項 HTTP 回應碼,則通知會被視為傳送成功:
    • 102 處理中
    • 200 成功
    • 201 已建立
    • 202 已接受
    • 204 沒有內容
  • 應用程式傳回的任何其他 HTTP 回應碼都會被視為永久失敗,不會重試。

用戶端應用程式範例

本節說明如何建立處理變更通知事件的 App Engine 用戶端應用程式。

下圖顯示在接收通知的過程 (從建立值區到處理相關變更通知事件) 中涉及的基本事件時間軸:

物件變更通知時間軸
物件變更通知時間軸

範例應用程式含有一個名為 MainPage 的類別。當使用者在值區中更新或新增物件時,MainPage 類別會處理通知事件。為了簡單起見,執行實際處理的 post 方法只會記錄訊息與收到通知的時間。您可以將此代碼替換成實際處理邏輯。如果您還不熟悉如何開發 App Engine 應用程式,請先試著部署範例應用程式,或遵循教學課程的操作說明,然後再繼續。

  1. 設定應用程式
    建立 app.yaml 設定檔,以指定處理值區變更通知事件的用戶端應用程式。
    application: <ApplicationId>
    version: 1
    runtime: python27
    api_version: 1
    threadsafe: true
    
    handlers:
    - url: /.*
      script: change_notification_client.app
    
  2. 建立應用程式
    下列範例實作處理值區變更通知事件的用戶端應用程式。請將它命名為 change_notification_client.py,然後部署應用程式:
    """Notification handling for Google Cloud Storage."""
    
    import json
    import logging
    
    import webapp2
    
    class MainPage(webapp2.RequestHandler):
      """Process notification events."""
      def get(self):
        logging.info("Get request to notification page.")
        self.response.write("Welcome to the notification app.")
    
      def post(self):  # pylint: disable-msg=C6409
        """Process the notification event.
    
        This method is invoked when the notification channel is first created with
        a sync event, and then subsequently every time an object is added to the
        bucket, updated (both content and metadata) or removed. It records the
        notification message in the log.
        """
    
        logging.debug(
            '%s\n\n%s',
            '\n'.join(['%s: %s' % x for x in self.request.headers.iteritems()]),
            self.request.body)
    
        # The following code is for demonstration. Replace
        # it with your own notification processing code.
    
        if 'X-Goog-Resource-State' in self.request.headers:
          resource_state = self.request.headers['X-Goog-Resource-State']
          if resource_state == 'sync':
            logging.info('Sync message received.')
          else:
            an_object = json.loads(self.request.body)
            bucket = an_object['bucket']
            object_name = an_object['name']
            logging.info('%s/%s %s', bucket, object_name, resource_state)
        else:
          logging.info("Other post.")
    
    logging.getLogger().setLevel(logging.DEBUG)
    app = webapp2.WSGIApplication([('/', MainPage)], debug=True)
    
  3. 指派應用程式針對值區的存取權限
    如果擁有值區的服務帳戶與 App Engine 應用程式不同,請執行下列指令,將值區的擁有者存取權授予應用程式:
    gsutil acl ch -u ApplicationId@appspot.gserviceaccount.com:OWNER gs://BucketName
    
  4. 開始監控值區中的物件變更
    使用 gsutil 監控值區,以建立應用程式的通知管道:
    gsutil notification watchbucket ApplicationUrl gs://BucketName
    
    其中 ApplicationUrl 是 App Engine 應用程式的網址,例如 https://ApplicationId.appspot.com/
  5. 測試應用程式
    如要查看應用程式是否如預期運作,請執行下列步驟:
    1. 如要確保應用程式已部署並正確運作,請執行下列的 curl 指令:
      curl -X Post https://<ApplicationId>.appspot.com
      
      如果您使用自有網域名稱來部署應用程式,請在之前的指令中使用該網域來代替 appspot.com
    2. 前往專案的「Logging」(記錄) 頁面。視需要重新整理記錄訊息清單。請確認應用程式發出的記錄訊息皆已記錄在內。
    3. 將物件新增至值區。您可以依照下列指令使用 gsutil 工具:
      gsutil cp ObjectName gs://BucketName/
      
      Cloud Storage 會通知應用程式,然後應用程式會記錄訊息。
    4. 前往專案的「Logging」(記錄) 頁面。重新整理記錄訊息清單,然後找出物件複本的訊息。
  6. 移除通知管道
    如要移除通知管道,請指定發出監控值區的通知指令時傳回的管道和資源 ID。
    gsutil notification stopchannel <channel_id> <resource_identifier>
    

返回頁首

本頁內容對您是否有任何幫助?請提供意見:

傳送您對下列選項的寶貴意見...

這個網頁
Cloud Storage
需要協助嗎?請前往我們的支援網頁