对象更改通知

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

您应该使用对象更改通知吗?

通常,您不应使用对象更改通知。建议将适用于 Cloud Storage 的 Pub/Sub 通知用于生成跟踪 Cloud Storage 存储桶中对象更改的通知,因为该工具更快速、更灵活,更易于设置且更经济高效。如需查看如何设置适用于 Cloud Storage 的 Pub/Sub 通知的分步指南,请参阅配置适用于 Cloud Storage 的 Pub/Sub 通知

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

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

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

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

对象更改通知详情

术语

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

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

监控存储桶

如需开始监控存储桶中的更改通知事件,请发出 watchAll 请求。此命令将为指定存储桶创建通知渠道,以便向指定 address 发送通知事件。此通知渠道包含自定义客户端令牌和渠道标识符(如果已指定)。

以下是监控存储桶的 POST 请求示例:

POST /storage/v1/b/BucketName/o/watch?alt=json HTTP/1.1
Host: storage.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 控制台项目。这意味着,例如,如果用户通过 OAuth2 流程向安装的应用或 Web 应用授予访问权限,那么由该应用创建的通知渠道将关联到应用所属的项目,而不是所监控存储桶所属的项目。

由于服务账号与项目关联,因此如果您使用服务账号监控存储桶,则系统会在该服务账号所属的项目中创建通知渠道。

移除通知渠道

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

以下是停止通知渠道的 POST 请求示例:

POST /storage/v1/channels/stop HTTP/1.1
Host: storage.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://storage.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://storage.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://content-storage.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 内部服务器错误
    • 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: APPLICATION
    version: 1
    runtime: python38
    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 访问权限。
  4. 开始监控存储桶中的对象更改
    创建指向应用的通知渠道,具体方法是使用 watchAll 请求以及 App Engine 应用网址的 address(例如 https://ApplicationId.appspot.com/)来监控存储桶。
  5. 测试应用
    如需查看该应用是否按预期运行,请按下述步骤操作:
    1. 如要确保应用已部署并正常运作,请执行以下 curl 命令:
      curl -X Post https://APPLICATION_ID.appspot.com
      
      如果您使用自己的域名来部署应用,请在之前的命令中使用该域名来代替 appspot.com
    2. 转至项目的日志记录页面。如果需要,可刷新记录消息列表。验证该应用发出的日志消息是否已记录。
    3. 向存储桶添加对象。Cloud Storage 会向应用发送通知,而应用随后会记录一条消息。
    4. 转至项目的日志记录页面。刷新记录消息列表,并找到与对象副本相关的消息。
  6. 移除通知渠道
    如需移除通知渠道,请指定在您发出用于监控存储桶的通知命令时系统返回的渠道标识符和资源标识符。