对象更改通知


使用对象更改通知功能,您可以在有对象发生更新或添加至存储分区时通知应用。

请注意,此功能不同于适用于 Cloud Storage 的 Cloud Pub/Sub 通知。若要跟踪 Cloud Storage 存储分区中对象的更改,我们建议您使用 Cloud Pub/Sub 通知功能,因为该功能速度更快、灵活性更高、设置更简单,而且成本效益更高。

对象更改通知功能的工作原理

客户端应用可以发送监控特定存储分区中对象更改的请求。

完成监控请求即会创建新的通知渠道。 通知消息会通过通知渠道发送到监控存储分区的应用。 目前仅支持网络钩子这一种通知渠道类型。

通知渠道启动后,无论何时存储分区发生添加、更新或移除对象的情况,Cloud Storage 都会立即通知相关应用。 例如,如果您向存储分区添加了新图片,相关应用则会收到创建缩略图的通知。

下图显示了处理更改通知的应用数据流示例。 您可以使用任何能够接收 HTTPS POST 请求的应用服务器来处理更改通知。

对象更改通知组件
对象更改通知组件

对象更改通知详情

术语

下表介绍了对象更改通知功能文档中使用的几个术语:

术语 说明
应用网址 您的应用的网址。这是将接收通知的地址。请注意,此网址必须是 HTTPS 网址;不允许使用 HTTP 网址。
渠道标识符 通知渠道的标识符。 此标识符在特定存储分区中不得重复,也就是说,如果一个存储分区存在多条通知渠道,则各通知渠道的渠道标识符必须各不相同。 此标识符将随每条通知消息一起发送到您的应用。
资源标识符 所监控资源的不透明标识符。 如需停止某条通知渠道,您必须提供其资源标识符。 您可以从监控请求的响应中或从通知事件消息的 X-Goog-Resource-Id 标头中检索此标识符。
客户端令牌 (可选)客户端令牌可用于验证通知事件。如要执行此操作,请通过您的监控请求设置自定义客户端令牌。通知消息将包含此令牌,以便您验证这些消息是否真实可信。

监控存储分区

如要开始监控存储分区中的更改通知事件,您可以使用 gsutil notification watchbucket 命令:

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

此命令将为指定存储分区创建通知渠道,以便向指定应用网址发送通知事件。 此通知渠道将包含自定义客户端令牌和渠道标识符(如果已指定)。

如需详细了解此命令,请运行 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 Console 项目。这意味着,例如,如果用户通过 OAuth2 流程向安装的应用或 Web 应用授予访问权限,那么由该应用创建的通知渠道将关联到应用所属的项目,而不是所监控存储分区所属的项目。

如需在对象更改通知场景中配置授权,您需要完成以下三个步骤:

创建服务帐号

由于服务帐号与项目关联,因此使用服务帐号监控存储分区将会在该服务帐号所属的项目中创建通知渠道。

您应该使用现有服务帐号或创建新帐号,然后下载关联的私钥

将 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 Console 中的凭据页面,然后生成一个新密钥。
  3. 确认此服务帐号是具有凭据的活跃帐号。
    $ gcloud auth list
    Credentialed accounts:
    - 1234567890123-abcdefghijklmonpqrstuvwxz01234567@developer.gserviceaccount.com (active)
    

    您应该会看到服务帐号凭据旁显示 active。 现在,您运行的所有 gsutil 对象通知命令都将使用这些服务帐号凭据。

标识要接收通知的网域

只有在通知网址是通知渠道所属项目的白名单网域时,监控请求才会成功。

如需将某个网域列入白名单,请使用以下命令

  1. 使用 Search Console 验证过程来验证您是否拥有该网域。
  2. 在 GCP Console 中,转到凭据页面上的网域验证标签页。

    转到“凭据”页面

  3. 点击添加网域
  4. 配置 Webhook 通知对话框中,输入要验证的网域。

    配置 webhook 通知对话框

  5. 点击添加网域

    要排查网域验证问题,请按如下所述操作:

    • 您必须在 Search Console 中使用 https:// 网址注册网域,或者已使用域名提供商验证方法验证网域。
    • 确保您是 GCP Console 项目的所有者或编辑者(请参阅项目成员和权限),并且您是将接收通知的网域的网站所有者。如果您不是该网域的网站所有者,请与网域所有者联系,以将您添加为经过验证的所有者(请参阅添加或移除所有者)。
    • 您可以使用网站站长工具中的 Google API Explorer 列出网域上的网站,特别是查看网域的 siteUrl 属性是否以 https:// 开头。

移除通知渠道

如需停止通知渠道,可以使用 gsutil notification stopchannel 命令:

gsutil notification stopchannel ChannelId ResourceId

此命令将停止与一对指定资源标识符和渠道标识符相关的所有通知事件。 与同一资源相关的其他活跃渠道不会受影响。 资源标识符和渠道标识符可以在监控请求的响应中或通知事件消息的正文中找到。

如需详细了解此命令,请运行 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 分钟的最长重试间隔后,系统将每隔 90 分钟重试一次并持续 7 天。如果在此期间内通知仍无法送达,系统则会清除该通知。
  • 如果您的应用在尝试 20 秒后仍无法访问,或者您的应用返回下列 HTTP 响应代码之一,系统会认为通知发送尝试失败并进行重试:
    • 500 Internal Server Error
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout
  • 如果您的应用返回下列 HTTP 响应代码之一,则系统会认为通知已成功发送:
    • 102 Processing
    • 200 OK
    • 201 Created
    • 202 Accepted
    • 204 No Content
  • 如果您的应用返回其他任何 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 应用不同,请运行以下命令,以向应用授予存储分区的 OWNER 访问权限:
    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. 转至项目的日志记录页面。如果需要,可刷新记录消息列表。验证该应用发出的日志消息是否已记录。
    3. 向存储分区添加对象。您可以按如下所示使用 gsutil 工具:
      gsutil cp ObjectName gs://BucketName/
      
      Cloud Storage 会向应用发送通知,而应用随后会记录一条消息。
    4. 转至项目的日志记录页面。刷新记录消息列表,并找到与对象副本相关的消息。
  6. 移除通知渠道
    如需移除通知渠道,请指定在您发出用于监控存储分区的通知命令时系统返回的渠道标识符和资源标识符。
    gsutil notification stopchannel <channel_id> <resource_identifier>
    

返回页首

此页内容是否有用?请给出您的反馈和评价:

发送以下问题的反馈:

此网页
Cloud Storage
需要帮助?请访问我们的支持页面