本文档介绍了如何使用推送通知,以在资源发生更改时通知您的应用。
概览
Google 日历 API 提供推送通知,可让您监控资源的变化。您可以使用此功能来提高应用的性能。这样,您就可以避免轮询资源以确定资源是否已更改所涉及的额外网络和计算费用。每当受监控的资源发生变化时,Google Calendar API 都会通知您的应用。
如要使用推送通知,您必须执行以下两项操作:
设置您的接收网址或“webhook”回调接收器。
这是一个 HTTPS 服务器,用于处理资源发生更改时触发的 API 通知消息。
请为您要监控的每个资源端点设置通知渠道。
渠道用于指定通知消息的路由信息。在频道设置过程中,您必须确定希望接收通知的具体网址。每当频道的资源发生变化时,Google Calendar API 都会以
POST
请求的形式向该网址发送通知消息。
目前,Google 日历 API 支持在 Acl、CalendarList、Events 和设置资源发生更改时发出通知。
创建通知渠道
如需请求推送通知,您必须为要监控的每个资源设置通知渠道。设置好通知渠道后,Google Calendar API 会在任何受监控的资源发生更改时通知您的应用。
发出观看请求
每项可观看的 Google Calendar API 资源都有一个关联的 watch
方法,其 URI 采用以下格式:
https://www.googleapis.com/API_NAME/API_VERSION/RESOURCE_PATH/watch
如需为有关特定资源更改的消息设置通知渠道,请向该资源的 watch
方法发送 POST
请求。
每个通知渠道都与特定用户和特定资源(或一组资源)相关联。除非当前用户拥有此资源或有权访问此资源,否则 watch
请求不会成功。
示例
开始监控给定日历上一系列活动的变化:
POST https://www.googleapis.com/calendar/v3/calendars/my_calendar@gmail.com/events/watch Authorization: Bearer auth_token_for_current_user Content-Type: application/json { "id": "01234567-89ab-cdef-0123456789ab", // Your channel ID. "type": "web_hook", "address": "https://mydomain.com/notifications", // Your receiving URL. ... "token": "target=myApp-myCalendarChannelDest", // (Optional) Your channel token. "expiration": 1426325213000 // (Optional) Your requested channel expiration time. }
必需属性
您必须为每个 watch
请求提供以下字段:
-
id
属性字符串,用于唯一标识项目中的这个新通知渠道。我们建议使用通用唯一标识符 (UUID) 或任何类似的唯一字符串。长度上限:64 个字符。您设置的 ID 值会回显在您针对此渠道收到的每条通知消息的
X-Goog-Channel-Id
HTTP 标头中。 -
一个设置为
web_hook
值的type
属性字符串。 -
address
属性字符串,已设为监听和响应此通知渠道的通知的网址。这是您的 webhook 回调网址,必须使用 HTTPS。请注意,只有当您的网络服务器上安装了有效的 SSL 证书时,Google 日历 API 才能向此 HTTPS 地址发送通知。无效的证书包括:
- 自签发证书
- 由不受信任的来源签发的证书
- 已被撤消的证书
- 证书的主题与目标主机名不匹配。
可选属性
您还可以在 watch
请求中指定以下可选字段:
-
token
属性,用于指定要用作通道令牌的任意字符串值。您可以将通知渠道令牌用于各种目的。例如,您可以使用令牌验证每封邮件是否都针对您的应用创建的通道(确保通知不被伪造),或根据此通道的用途将消息路由到您应用中的正确目标位置。长度上限:256 个字符。令牌包含在应用针对此渠道收到的每条通知消息的
X-Goog-Channel-Token
HTTP 标头中。如果您使用通知渠道令牌,我们建议您:
使用可扩展的编码格式,例如网址查询参数。示例:
forwardTo=hr&createdBy=mobile
请勿包含 OAuth 令牌等敏感数据。
-
expiration
属性字符串,设置为您希望 Google Calendar API 停止为此通知渠道发送消息的日期和时间的 Unix 时间戳(以毫秒为单位)。如果某个渠道有到期时间,则系统会将其作为
X-Goog-Channel-Expiration
HTTP 标头的值(采用人类可读懂的格式)包含在您的应用针对此渠道收到的每条通知消息中。
如需详细了解该请求,请参阅 API 参考文档中 Acl、CalendarList、Events 和 Settings 资源的 watch
方法。
观看回复
如果 watch
请求成功创建了通知渠道,则会返回 HTTP 200 OK
状态代码。
监视响应的消息正文提供您刚刚创建的通知渠道的相关信息,如以下示例所示。
{ "kind": "api#channel", "id": "01234567-89ab-cdef-0123456789ab"", // ID you specified for this channel. "resourceId": "o3hgv1538sdjfh", // ID of the watched resource. "resourceUri": "https://www.googleapis.com/calendar/v3/calendars/my_calendar@gmail.com/events", // Version-specific ID of the watched resource. "token": "target=myApp-myCalendarChannelDest", // Present only if one was provided. "expiration": 1426325213000, // Actual expiration time as Unix timestamp (in ms), if applicable. }
除了您作为请求一部分发送的属性之外,返回的信息还包括 resourceId
和 resourceUri
,用于标识此通知渠道上所监控的资源。
您可以将返回的信息传递给其他通知渠道操作,例如当您想要停止接收通知时。
如需详细了解该响应,请参阅 API 参考文档中 Acl、CalendarList、Events 和 Settings 资源的 watch
方法。
同步信息
创建通知渠道以监控资源后,Google 日历 API 会发送 sync
消息,指示通知正在启动。这些消息的 X-Goog-Resource-State
HTTP 标头值为 sync
。由于网络计时问题,您甚至可能会在收到 watch
方法响应之前就收到 sync
消息。
您可以放心地忽略 sync
通知,不过您也可以使用它。例如,如果您决定不想保留频道,可以在调用中使用 X-Goog-Channel-ID
和 X-Goog-Resource-ID
值来停止接收通知。您还可以使用 sync
通知进行一些初始化,为以后的事件做好准备。
Google 日历 API 向您的接收网址发送的 sync
消息的格式如下所示。
POST https://mydomain.com/notifications // Your receiving URL. X-Goog-Channel-ID: channel-ID-value X-Goog-Channel-Token: channel-token-value X-Goog-Channel-Expiration: expiration-date-and-time // In human-readable format. Present only if the channel expires. X-Goog-Resource-ID: identifier-for-the-watched-resource X-Goog-Resource-URI: version-specific-URI-of-the-watched-resource X-Goog-Resource-State: sync X-Goog-Message-Number: 1
同步消息的 X-Goog-Message-Number
HTTP 标头值始终为 1
。此渠道的每个后续通知的消息编号都大于前一个通知编号,但消息编号不是连续的。
续订通知渠道
通知渠道可以有到期时间,其值取决于您的请求或任何 Google 日历 API 内部限制或默认值(使用限制性更强的值)。通道的到期时间(如果有)将以 Unix 时间戳(以毫秒为单位)的形式添加到 watch
方法返回的信息中。此外,失效日期和时间以人类可读的格式包含在应用收到的关于此渠道的每条通知消息中,具体位于 X-Goog-Channel-Expiration
HTTP 标头中。
目前没有自动续订通知渠道的方法。当某个渠道即将到期时,您必须通过调用 watch
方法来将其替换为新渠道。与往常一样,您必须为新渠道的 id
属性使用一个唯一值。请注意,当同一资源的两个通知渠道处于活动状态时,可能会存在“重叠”时间段。
接收通知
每当受监控的资源发生更改时,您的应用都会收到描述更改的通知消息。Google Calendar API 会将这些消息作为 HTTPS POST
请求发送到您指定为此通知渠道的 address
属性的网址。
解读通知消息格式
所有通知消息均包含一组带有 X-Goog-
前缀的 HTTP 标头。
某些类型的通知还可以包含消息正文。
标头
Google Calendar API 发布到您的接收网址的通知消息包含以下 HTTP 标头:
标题 | 说明 |
---|---|
始终存在 | |
|
您提供的用于标识此通知渠道的 UUID 或其他唯一字符串。 |
|
用于标识此通知渠道的此消息的整数。对于 sync 消息,值始终为 1 。通道上的每条后续消息的消息编号都会增加,但这些消息没有顺序性。 |
|
标识受监控的资源的不透明值。此 ID 在各 API 版本中都是稳定的。 |
|
触发通知的新资源状态。
可能的值:sync 、exists 或 not_exists 。 |
|
受监控资源的 API 版本特定标识符。 |
偶尔出现 | |
|
通知渠道到期的日期和时间,采用人类可读懂的格式。仅在已定义时显示。 |
|
您的应用设置的通知渠道令牌,可用于验证通知来源。仅当已定义时存在。 |
由 Google 日历 API 发布到您的接收网址的通知消息不包含消息正文。这些消息不包含有关已更新资源的具体信息,您需要再次调用 API 才能查看完整的更改详情。
示例
针对修改后的事件集合更改通知消息:
POST https://mydomain.com/notifications // Your receiving URL. Content-Type: application/json; utf-8 Content-Length: 0 X-Goog-Channel-ID: 4ba78bf0-6a47-11e2-bcfd-0800200c9a66 X-Goog-Channel-Token: 398348u3tu83ut8uu38 X-Goog-Channel-Expiration: Tue, 19 Nov 2013 01:13:52 GMT X-Goog-Resource-ID: ret08u3rv24htgh289g X-Goog-Resource-URI: https://www.googleapis.com/calendar/v3/calendars/my_calendar@gmail.com/events X-Goog-Resource-State: exists X-Goog-Message-Number: 10
有关通知的操作
如需表示成功,您可以返回以下任一状态代码:200
、201
、202
、204
或 102
。
如果您的服务使用 Google 的 API 客户端库并返回 500
、502
、503
或 504
,则 Google Calendar API 会使用指数退避算法重试。
所有其他返回状态代码均会被视为消息失败。
了解 Google Calendar API 通知事件
本部分详细介绍了通过 Google Calendar API 使用推送通知时您可能会收到的通知消息。
送达时间 | ||
---|---|---|
sync |
ACL、日历列表、活动、设置。 | 已成功创建新渠道。您应该会开始收到其相关通知。 |
exists |
ACL、日历列表、活动、设置。 | 资源发生了更改。可能的更改包括创建新资源,或者修改或删除现有资源。 |
停止通知
expiration
属性用于控制何时自动停止通知。您可以选择停止在此频道过期之前停止接收特定频道的通知,只需调用以下 URI 处的 stop
方法即可:
https://www.googleapis.com/calendar/v3/channels/stop
此方法要求您至少提供频道的 id
和 resourceId
属性,如以下示例所示。请注意,如果 Google Calendar API 有多种类型的资源具有 watch
方法,则只有一个 stop
方法。
只有拥有适当权限的用户才能停止频道。具体而言:
- 如果渠道是由常规用户帐号创建的,则只有来自同一客户端(通过身份验证令牌中的 OAuth 2.0 客户端 ID 来识别)的同一用户才能停止该渠道。
- 如果渠道是由服务帐号创建的,则来自同一客户端的任何用户都可以停止该渠道。
以下代码示例展示了如何停止接收通知:
POST https://www.googleapis.com/calendar/v3/channels/stop Authorization: Bearer CURRENT_USER_AUTH_TOKEN Content-Type: application/json { "id": "4ba78bf0-6a47-11e2-bcfd-0800200c9a66", "resourceId": "ret08u3rv24htgh289g" }