Copyright © 2025 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
推送 API 允许通过 推送服务 向 Web 应用发送 推送消息。应用服务器 可以在任何时间发送 推送消息,即使 Web 应用或 用户代理 处于非活动状态。推送服务 能确保消息可靠高效地传递给 用户代理。推送消息会发送到运行在 Web 应用源下的 Service Worker,Service Worker 可以使用消息中的信息更新本地状态或向用户显示通知。
本节描述了本文档在发布时的状态。当前 W3C 出版物列表及本技术报告的最新修订版可在 W3C 标准与草案索引中查阅。
作为工作草案发布不代表 W3C 及其成员的认可。
本文档为草稿,可能随时被更新、替换或废弃。除作为正在进行的工作外,不应引用本文件。
本文档由遵循 W3C 专利政策的工作组编制。 W3C维护着 与工作组交付物相关的专利公开的公开列表; 该页面还包括专利披露的说明。任何知晓包含 必要声明 的专利的个人,必须根据 《W3C 专利政策》第 6 节披露相关信息。
本文档受 2025 年 8 月 18 日 W3C 流程文件约束。
本节为非规范性内容。
推送 API 允许 Web 应用与 用户代理 异步通信。这使得 应用服务器 能够在信息变得可用时,及时向 用户代理 提供时效性信息,而无需等待用户打开 Web 应用。
特别地,即使 Web 应用当前未在浏览器窗口中活动,推送消息也会被投递到 Web 应用:这适用于用户关闭 Web 应用但仍希望在收到推送消息时能重新启动 Web 应用的场景。例如,推送消息可用于通知用户有来电的 WebRTC 呼叫。
当用户代理临时离线时,也可发送推送消息。对此,推送服务会为用户代理存储消息,直到用户代理可用。这支持 Web 应用在用户离线期间获知变化,并确保用户代理能及时获得相关信息。推送消息由推送服务存储,直到用户代理可达且消息可被投递。
推送 API 也确保在用户代理主动使用 Web 应用时可靠投递推送消息,例如用户正在使用 Web 应用或 Web 应用通过活动 worker、frame 或后台窗口与应用服务器进行通信时。这并非推送 API 的主要应用场景。Web 应用可选择使用推送 API 发送不频繁的消息,以避免与 应用服务器保持持续的通信。
推送消息更适合于用户代理与 Web 应用之间尚未建立活动通信通道的场合。发送推送消息相比直接通信方式(如 Fetch API 或 [WebSockets])消耗更多资源。推送消息通常比直接通信延迟更高,并且可能受限于使用条件。大多数推送服务会限制可发送推送消息的大小和数量。
Web 推送协议 [RFC8030] 描述了一种协议,使 用户代理 或 应用服务器 能够与 推送服务通信。可以使用其他协议替代本协议,但本规范假定采用该协议;其他协议应提供兼容语义。
Content-Encoding
HTTP 头部,由 [RFC7231] 第 3.1.2.2
节描述,指示应用于推送消息负载的内容编码方式。
应用服务器一词指 Web 应用的服务端组件。
推送消息是从应用服务器发送到 Web 应用的数据。
推送消息会投递到与消息所提交的推送订阅相关联的活动 worker。如果 Service Worker 当前未运行,则会启动 worker 以进行消息投递。
声明式推送消息是一个推送消息,其数据为用户代理能够理解的 JSON 文档。用户代理会机会性地解析每个收到的 推送消息,以判断其是否为声明式推送消息,解析过程使用 声明式推送消息解析器。
声明式推送消息允许创建和显示通知,无需 Service Worker 的参与。当然,如果 应用服务器需要,Service Worker 仍可以参与。在这种情况下,推送消息的声明式属性可作为备用,例如 Service Worker 因存储压力被驱逐时。同时,这种方式为通知数据的传递提供了更面向对象的方案。
{
"web_push": 8030,
"notification": {
"title": "Ada emailed ‘London’",
"lang": "en-US",
"dir": "ltr",
"body": "Did you hear about the tube strikes?",
"navigate": "https://email.example/message/12"
}
}
声明式推送消息包含以下成员:
web_push
(必填)
一个整数,值必须为 8030。用于将声明式推送消息 与其它 JSON 文档区分开。
notification
(必填)
一个 JSON 对象,包含如下成员,均类似于 Notifications API 的特性,但类型有时更严格。除 title
外,所有成员均来自 NotificationOptions
字典,并需保持同步。 [NOTIFICATIONS]
title
(必填)
字符串。
dir
"auto
"、"ltr
" 或 "rtl
"。
lang
表示语言标签的字符串。
body
字符串。
navigate
(必填)
表示 URL 的字符串。
tag
字符串。
image
表示 URL 的字符串。
icon
表示 URL 的字符串。
badge
表示 URL 的字符串。
vibrate
32 位无符号整数数组。
timestamp
renotify
布尔值。
silent
布尔值。
requireInteraction
布尔值。
该字段未命名为 require_interaction
,以与 NotificationOptions
字典保持一致。
data
任意 JSON 值。
actions
JSON 对象数组,包含如下成员,均来自 NotificationAction
字典,并需保持同步。
action
(必填)
字符串。
title
(必填)
字符串。
navigate
(必填)
表示 URL 的字符串。
icon
表示 URL 的字符串。
mutable
布尔值。当为 true 时,会向(如有)Service Worker 分发包含该Notification
对象的 push
事件,该对象由
声明式推送消息描述。
声明式推送消息解析器结果是一个元组,包含 notification(一个 notification)和 mutable(一个布尔值)。
声明式推送消息解析器给定一个字节序列
bytes、origin
origin、URL
baseURL,以及
EpochTimeStamp
fallbackTimestamp,执行如下步骤。它们返回失败或声明式推送消息解析器结果。
令 message 为 解析 JSON 字节为 Infra 值的结果,参数为 bytes。若抛出异常,则返回失败。
若 message 不是有序映射,则返回失败。
若 message["web_push
"] 不存在或不是 8030,则返回失败。
若 message["notification
"] 不存在,则返回失败。
令 notificationInput = message["notification
"]。
若 notificationInput 不是有序映射,则返回失败。
若 notificationInput["title
"] 不存在或不是字符串,则返回失败。
若 notificationInput["navigate
"] 不存在或不是字符串,则返回失败。
令 notificationTitle = notificationInput["title
"]。
令 notificationOptions 为 NotificationOptions
字典。
若 notificationInput["dir
"]存在且值为"auto
"、"ltr
"或"rtl
",则设置
notificationOptions["dir
"]
为 notificationInput["dir
"]。
若 notificationInput["lang
"]存在且为字符串,则设置
notificationOptions["lang
"]
为
notificationInput["lang
"]。
若 notificationInput["body
"]存在且为字符串,则设置
notificationOptions["body
"]
为
notificationInput["body
"]。
设置 notificationOptions["navigate
"]
为
notificationInput["navigate
"],并转换。
若 notificationInput["tag
"]存在且为字符串,则设置
notificationOptions["tag
"]
为
notificationInput["tag
"]。
若 notificationInput["image
"]存在且为字符串,则设置
notificationOptions["image
"]
为
notificationInput["image
"],并转换。
若 notificationInput["icon
"]存在且为字符串,则设置
notificationOptions["icon
"]
为
notificationInput["icon
"],并转换。
若 notificationInput["badge
"]存在且为字符串,则设置
notificationOptions["badge
"]
为
notificationInput["badge
"],并转换。
若 notificationInput["vibrate
"]存在且为列表,且每个项
都是32
位无符号整数,则设置
notificationOptions["vibrate
"]
为
notificationInput["vibrate
"]。
若 notificationInput["timestamp
"]存在且为64 位无符号整数,则设置
notificationOptions["timestamp
"]
为
notificationInput["timestamp
"]。
若 notificationInput["renotify
"]存在且为布尔值,则
设置 notificationOptions["renotify
"]
为
notificationInput["renotify
"]。
若 notificationInput["silent
"]存在且为布尔值,则
设置 notificationOptions["silent
"]
为
notificationInput["silent
"]。
若 notificationInput["requireInteraction
"]存在且为布尔值,则设置
notificationOptions["requireInteraction
"]
为
notificationInput["requireInteraction
"]。
若 notificationInput["data
"]存在,则设置
notificationOptions["data
"]
为运行 将
Infra 值转换为 JSON 兼容的 JavaScript 值的结果,参数为
notificationInput["data
"]。
若 notificationInput["actions
"]存在且为列表:
令 notificationActions = « »。
对每个
actionInput 属于
notificationInput["actions
"]:
令 actionNavigate =
actionInput["navigate
"],
转换。
令 notificationAction 为 NotificationAction
字典
«[ "action
"
→ actionInput["action
"],
"title
"
→ actionInput["title
"],
"navigate
"
→ actionNavigate ]»。
若 actionInput["icon
"]存在且为字符串,则
设置 notificationAction["icon
"]
为
actionInput["icon
"],并转换。
追加 notificationAction到 notificationActions。
设置 notificationOptions["actions
"]
为
notificationActions。
令 notification 为运行 创建通知,参数为 notificationTitle、notificationOptions、origin、 baseURL 和 fallbackTimestamp 的结果。若抛出异常,则返回失败。
若 notification 的导航 URL为 null,则返回失败。
令 mutable = false。
若 message["mutable
"]存在且
message["mutable
"] 为布尔值,则设置 mutable 为
message["mutable
"]。
返回 (notification, mutable)。
推送订阅是为 Web 应用在 用户代理与 推送服务之间建立的消息传递上下文。
推送订阅有一个关联的 scope(作用域),它是一个 URL。
当推送订阅的 scope的 path为 list,长度为 1,且 scope的 path[0]为空字符串时,认为其具有 窗口可访问作用域。
推送订阅有一个关联的 推送端点。 它必须是由 推送服务公开的绝对 URL, 应用服务器可向其发送 推送消息。 推送端点 必须唯一标识该 推送订阅。
推送订阅 可以有一个关联的 订阅过期时间。 设置时,它必须是自 1970 年 1 月 1 日 00:00:00 UTC 起的毫秒数,到该时间点订阅将被 停用。 用户代理 应当在订阅过期前尝试 刷新推送订阅。
推送订阅 有用于 P-256 ECDH 密钥对和认证密钥的内部槽,符合 [RFC8291]。 在创建推送订阅时,这些槽 必须被填充。
如果用户代理因任何原因需要更换 推送订阅的密钥, 且推送订阅的 关联 Service Worker 注册非空, 则必须 刷新 推送订阅。
要创建推送订阅,给定
PushSubscriptionOptionsInit
optionsDictionary:
PushSubscription
。
PushSubscriptionOptions
对象,属性由 optionsDictionary 的相应成员和值初始化。
options
属性设置为 options。
getKey
()
并传递参数 "p256dh
" 获取。
getKey
()
并传递参数 "auth
" 获取该密钥。
applicationServerKey
属性,则一同发送。重新抛出任何
异常。
endpoint
属性设置为
推送订阅的
推送端点。
expirationTime
。
推送订阅的 关联 Service Worker 注册 是其 Service Worker 注册, 当其 scope URL 等于 推送订阅的 scope 时(如果有);否则为 null。
推送订阅的 关联 Service Worker 注册 只有在其具有 窗口可访问作用域 时才可能为 null。
反过来, Service Worker 注册的 关联推送订阅 是其 推送订阅, 当其 scope 等于 Service Worker 注册的 scope URL 时(如果有);否则为 null。
user agent 或者 push service MAY 选择 refresh 一个 push subscription,当它的 associated service worker registration 在任何时候都不是 null 的时候,例如因为它已经达到了一定的时间。
当这种情况发生时,用户代理
必须按照用于创建当前
推送订阅
时所提供的
PushSubscriptionOptions
,运行创建推送订阅的步骤,
并将新推送订阅的
scope
设置为原始订阅的scope。
新的推送订阅
必须拥有与原订阅不同的密钥对。
当刷新成功时,用户代理
必须
触发
"pushsubscriptionchange
" 事件,
事件参数为与推送订阅相关联的
Service Worker
注册
作为 registration,
表示初始推送订阅的
PushSubscription
实例作为 oldSubscription,
表示新推送订阅的
PushSubscription
实例作为 newSubscription。
为了让更改有时间传播到应用服务器, 用户代理 可以在刷新后短暂继续接受旧推送订阅的消息。 一旦收到刷新后的推送订阅的消息, 所有旧的推送订阅 必须被停用。
如果用户代理
无法刷新推送订阅,
则应当定期重试刷新。
当推送订阅无法再使用,
例如因其已过期时,用户代理
必须
触发
"pushsubscriptionchange
" 事件,
事件参数为与推送订阅相关联的
Service Worker
注册
作为 registration,
表示即将停用的推送订阅的
PushSubscription
实例作为 oldSubscription,
并将 newSubscription 设为 null
。
当推送订阅 被停用时, 用户代理和 推送服务 必须删除其详细信息的所有已存储副本。后续针对该 推送订阅 的推送消息 不得被投递。
一个没有 窗口可访问范围的推送订阅,在其关联的 service worker 注册被注销时必须被停用,不过推送订阅可以被停用得更早。
没有窗口可访问作用域 的推送订阅 会在Service Worker 注册 被清除时移除。
推送服务 指的是一种允许应用服务器向 Web 应用发送 推送消息的系统。 推送服务为其所服务的推送订阅 提供推送端点或 端点。
用户代理 会连接用于创建推送订阅的 推送服务。 用户代理 可以限制可用的推送服务的选择。 这样做的原因包括与性能相关的考虑,例如服务可用性(包括服务是否在特定国家或工作场所等网络被防火墙阻断)、可靠性、对电池寿命的影响,以及将元数据导向或避开特定 推送服务的协议等。
Push API 是一个被 强大功能识别的功能, 其名称为 "push"。
为了与Permissions规范集成,
本规范定义了
PushPermissionDescriptor
权限描述符类型。
WebIDLdictionary PushPermissionDescriptor
: PermissionDescriptor {
boolean userVisibleOnly
= false;
};
userVisibleOnly
具有与
userVisibleOnly
相同的语义。
{name: "push", userVisibleOnly: false}
强于
{name: "push", userVisibleOnly: true}
。
推送消息的内容是加密的 [RFC8291]。但 推送服务 仍然可以看到应用服务器通过推送订阅向 用户代理发送消息时的元数据,包括消息的时间、频率和大小。除了更换 推送服务 (用户代理可能不允许),已知的缓解措施只有通过填充数据来增加表观消息大小。
无法保证推送消息是由与 Web 应用同源的 应用服务器发送的。 应用服务器可以自行决定将使用 推送订阅所需的详细信息分享给第三方。
以下要求旨在尽可能保护用户的隐私和安全,同时在实现该目标的前提下,保护 应用服务器与用户通信的完整性。
用户代理
不得在未获得用户
明确许可
的情况下向 Web 应用开放 Push API。
用户代理
必须通过用户界面在每次调用 subscribe()
方法时获取许可,
除非之前的许可已被持久保存或存在预先安排的信任关系。
超出当前浏览会话保存的权限必须可被撤销。
Push API 可能需要唤醒与 Service Worker 注册 关联的 Service Worker,以运行开发者提供的事件处理器。这可能会导致资源消耗,比如网络流量, 用户代理 应当将这些消耗归因于创建 推送订阅的 Web 应用。
用户代理
可以在获取权限或判断权限状态时考虑
PushSubscriptionOptions
。
当权限被撤销时,
用户代理
可以为使用该权限创建的订阅
触发 "pushsubscriptionchange
"
事件,
事件参数为与
Service Worker 注册
关联的
推送订阅作为 registration,
表示该推送订阅的
PushSubscription
实例作为 oldSubscription,
null
作为 newSubscription。
用户代理
必须并行
停用相关订阅。
推送端点 不得向 推送服务以外的参与方泄露可推断用户信息,如设备、身份或位置。 具体要求见 [RFC8030] 的隐私注意事项。
一个已停用的推送订阅的推送端点不得用于新的推送订阅。这可以防止创建用户无法删除的持久性标识符。这也防止了重复使用一个推送订阅的细节来向另一个推送订阅发送推送消息。
用户代理 必须实现 Push API 仅在 安全上下文 中可用。这样可以更好地防止针对推送订阅数据的中间人攻击。浏览器仅可在开发目的下忽略此规则。
本节为非规范性内容。
该整体框架允许应用服务器在发生事件时激活Service Worker。这些事件的信息可包含在推送消息中,从而使 Web 应用能适当响应相关事件,无需主动发起网络请求。
下列代码及流程图展示了推送 API 的一个假设使用场景。
本节为非规范性内容。
// https://example.com/serviceworker.js
this.onpush = event => {
console.log(event.data);
// 此处可以将数据写入 IndexedDB、发送到任何已打开窗口、显示通知等。
}
// https://example.com/webapp.js
// 在一个 async 函数内部...
try {
const serviceWorkerRegistration = await navigator.serviceWorker.register(
"serviceworker.js"
);
const pushSubscription = await serviceWorkerRegistration.pushManager.subscribe();
// 应用服务器所需的推送订阅详情现在已可用,可通过 XMLHttpRequest 等方式发送给服务器。
console.log(pushSubscription.endpoint);
console.log(pushSubscription.getKey("p256dh"));
console.log(pushSubscription.getKey("auth"));
} catch (err) {
// 在生产环境中,可能还需要将错误信息反馈给应用服务器。
console.log(error);
}
本节为非规范性内容。
PushSubscription
包含应用服务器发送 推送消息所需的全部信息。与 Push API 兼容的推送服务会提供符合 Web 推送协议的 推送端点。这些参数和属性包括:
本规范通过 PushManagerAttribute
混入,
扩展了 Window
和
ServiceWorkerRegistration
对象。
[HTML]
[SERVICE-WORKERS]
WebIDL[SecureContext]
interface mixin PushManagerAttribute
{
readonly attribute PushManager
pushManager
;
};
Window includes PushManagerAttribute
;
ServiceWorkerRegistration includes PushManagerAttribute
;
Window
和
ServiceWorkerRegistration
对象都拥有一个关联的 PushManager
对象。
pushManager
getter 步骤为返回 this 关联的
PushManager
对象。
在 Window
对象上,
PushManager
的
service worker registration 为 null。
在 ServiceWorkerRegistration
对象上,
PushManager
的
service worker registration
即为该
service worker
registration
所代表的
ServiceWorkerRegistration
对象。
PushManager
接口定义了访问
推送服务的操作。
WebIDL[Exposed=(Window,Worker), SecureContext]
interface PushManager
{
[SameObject] static readonly attribute FrozenArray<DOMString> supportedContentEncodings
;
Promise<PushSubscription
> subscribe
(optional PushSubscriptionOptionsInit
options = {});
Promise<PushSubscription
?> getSubscription
();
Promise<PermissionState> permissionState
(optional PushSubscriptionOptionsInit
options = {});
};
PushManager
具有一个关联的 service
worker 注册,其值为 null 或一个
service worker 注册。
supportedContentEncodings
属性公开了一系列可用于加密
推送消息
负载的内容编码。内容编码通过请求
推送服务发送
推送消息时的
Content-Encoding
头字段指示。
用户代理
必须支持 [RFC8291] 中定义的 aes128gcm
内容编码,
并且可以为了兼容性原因支持旧版本草案中定义的内容编码。
subscribe()
方法的步骤如下:
/
" 和
global 的 关联
Document
的 URL 的结果。
https
",
则在 networking
task source 上,
使用 global 拒绝
promise,抛出 "NotAllowedError
"
DOMException
。
userVisibleOnly
为 false
,而用户代理要求必须为 true
,
则拒绝 promise 并抛出 "NotAllowedError
"
DOMException
。
applicationServerKey
的非 null 值,且
推送服务 要求必须提供,
则拒绝 promise 并抛出 "NotSupportedError
"
DOMException
。
applicationServerKey
属性:
applicationServerKey
是 DOMString
,
则其值为通过 base64url 解码得到的八位字节序列
[RFC7515]。
InvalidCharacterError
"
DOMException
,终止后续步骤。
applicationServerKey
描述的是 P-256 曲线上的有效点。无效则拒绝 promise 并抛出 "InvalidAccessError
"
DOMException
,终止后续步骤。
InvalidStateError
"
DOMException
,终止后续步骤。
denied
",
则拒绝 promise 并抛出 "NotAllowedError
"
DOMException
,终止后续步骤。
AbortError
"
DOMException
,终止后续步骤。
options
属性对比,
BufferSource
的内容按值比较。
InvalidStateError
"
DOMException
,终止后续步骤。
PushSubscription
。
getSubscription()
方法的步骤如下:
/
" 和 global 的
关联
Document
的 URL 的结果。
DOMException
,
名称为 "AbortError
",终止后续步骤。
PushSubscription
。
permissionState()
方法被调用时
必须运行以下步骤:
PermissionDescriptor
,
其 name
初始化为 "push"。
使用推送服务的权限可以是持久的,即如果存在有效权限,则无需为后续订阅重新确认。
如果需要申请权限,应通过调用
subscribe
()
方法完成。
WebIDL[Exposed=(Window,Worker), SecureContext]
interface PushSubscriptionOptions
{
readonly attribute boolean userVisibleOnly
;
[SameObject] readonly attribute ArrayBuffer? applicationServerKey
;
};
userVisibleOnly
属性在获取时返回初始化值。
applicationServerKey
属性在获取时返回初始化值。
如果存在,applicationServerKey
的值必须包含一个 P-256 椭圆曲线上的点 [DSS],采用
[ANSI-X9-62]
附录 A 描述的未压缩格式(即 65 字节,首字节为 0x04)。如以 DOMString
提供,则值必须用 [RFC7515] 的 base64url 编码。
当 applicationServerKey
不存在且 推送服务因运维需要要求时,用户代理可以拒绝订阅请求。
applicationServerKey
的值必须与用于消息加密的密钥不同 [RFC8291]。
WebIDLdictionary PushSubscriptionOptionsInit
{
boolean userVisibleOnly
= false;
(BufferSource or DOMString)? applicationServerKey
= null;
};
userVisibleOnly
成员设置为
true
时,表示 推送订阅仅用于对用户可见效果的 推送消息,例如显示 Web
通知。[NOTIFICATIONS]
PushSubscriptionOptionsInit
表示与
推送订阅关联的附加选项。用户代理可以在向用户请求明确权限时考虑这些选项。如选项被考虑,用户代理应当在收到的 推送消息上强制执行相关约束。
这些选项是可选的,用户代理可以只支持其中一部分。用户代理不得暴露不支持的选项。
一旦设置,推送订阅的选项不可更改。已有的 推送订阅可通过 unsubscribe
退订,以创建带新选项的 推送订阅。
applicationServerKey
成员在与 推送服务建立 推送订阅时,由 用户代理使用。applicationServerKey
选项包含 应用服务器的椭圆曲线公钥。该密钥用于 应用服务器在向该 推送订阅发送 推送消息时进行身份验证,具体见 [RFC8292];推送服务会拒绝未用对应私钥生成认证令牌的 推送消息。
PushSubscription
对象表示一个 推送订阅。
WebIDL[Exposed=(Window,Worker), SecureContext]
interface PushSubscription
{
readonly attribute USVString endpoint
;
readonly attribute EpochTimeStamp? expirationTime
;
[SameObject] readonly attribute PushSubscriptionOptions
options
;
ArrayBuffer? getKey
(PushEncryptionKeyName
name);
Promise<boolean> unsubscribe
();
PushSubscriptionJSON
toJSON
();
};
dictionary PushSubscriptionJSON
{
USVString endpoint
;
EpochTimeStamp? expirationTime
= null;
record<DOMString, USVString> keys
;
};
当获取
endpoint
属性时,用户代理必须返回与该推送订阅关联的推送端点。用户代理
必须使用不包含依赖输入分支(即常数时间)的序列化方法。
当获取 expirationTime
属性时,用户代理必须返回与该推送订阅关联的订阅过期时间,如无则返回null
。
获取 options
属性时,用户代理必须返回一个
PushSubscriptionOptions
对象,表示该推送订阅的相关选项。
getKey()
方法用于检索可用于加密和认证消息的密钥材料。调用 getKey
()
时,执行以下过程:
name
参数指定的密钥名对应的内部槽。
null
。
ArrayBuffer
初始化变量
key。
p256dh
" 公钥采用 [ANSI-X9-62]
附录 A 的未压缩格式(65 字节,首字节为 0x04)。
auth
参数包含用户代理用于认证应用服务器发送消息的字节序列。
"p256dh
" 和 "auth
" 两个密钥名必须支持,且其值必须与用户代理根据 [RFC8291] 解密收到推送消息所需一致。
unsubscribe()
方法调用时必须执行如下步骤:
false
,终止后续步骤。
true
。
toJSON()
方法调用时必须执行如下步骤:
PushSubscriptionJSON
字典。
endpoint
属性的结果。
expirationTime
属性的结果。
record<DOMString, USVString>
实例。
PushSubscription
内部槽的每个标识符
i,按密钥名排序:
PushSubscriptionJSON
字典表示 JSON 类型的
PushSubscription
。在 ECMAScript 中可通过
JSON
.stringify
()
方法转换为 JSON 字符串。
keys
记录包含每个已支持 PushEncryptionKeyName
条目的 URL 安全 base64 编码表示
[RFC4648]。
注意:PushSubscription
的选项不会被序列化。
用于 推送消息加密的密钥通过 getKey
()
方法或 PushSubscription
的序列化器提供给 Web 应用。每个密钥都用 PushEncryptionKeyName
枚举中的值命名。
WebIDLenum PushEncryptionKeyName
{
"p256dh
",
"auth
"
};
p256dh
用于获取 [RFC8291] 描述的 P-256 ECDH Diffie-Hellman 公钥。
auth
用于获取 [RFC8291] 中描述的认证密钥。
WebIDL[Exposed=ServiceWorker, SecureContext]
interface PushMessageData
{
ArrayBuffer arrayBuffer
();
Blob blob
();
Uint8Array bytes
();
any json
();
USVString text
();
};
PushMessageData
对象有一个关联的 bytes(一个 字节序列),在创建时设置。
arrayBuffer()
方法的步骤是返回一个 ArrayBuffer
,其内容即 this 的 bytes。创建 ArrayBuffer
时抛出的异常会被重新抛出。
blob()
方法的步骤是返回一个新的 Blob
对象,其内容为 this 的 bytes。
bytes()
方法的步骤是返回一个新的 Uint8Array
,其底层 ArrayBuffer
的内容为 this 的 bytes。创建 ArrayBuffer
时抛出的异常会被重新抛出。
json()
方法的步骤是返回运行 解析 JSON 字节为 JavaScript
值,参数为 this 的 bytes。
text()
方法的步骤是对 this 的 bytes 运行 UTF-8 解码。
从 object 提取字节序列,步骤如下:
BufferSource
USVString
Service Worker 规范定义了 ServiceWorkerGlobalScope
接口
[SERVICE-WORKERS],本规范对其进行了扩展。
WebIDL[Exposed=ServiceWorker, SecureContext]
partial interface ServiceWorkerGlobalScope {
attribute EventHandler onpush
;
attribute EventHandler onpushsubscriptionchange
;
};
onpush
属性是一个 事件处理器 IDL
属性,
其对应的 事件类型 为
"push
"。"push
" 事件表示
推送消息已被投递到 推送订阅。
onpushsubscriptionchange
属性是一个 事件处理器 IDL
属性,
对应的 事件类型为
"pushsubscriptionchange
"。
WebIDL[Exposed=ServiceWorker, SecureContext]
interface PushEvent
: ExtendableEvent {
constructor
(DOMString type, optional PushEventInit
eventInitDict = {});
readonly attribute PushMessageData
? data
;
readonly attribute Notification? notification
;
};
dictionary PushEventInit
: ExtendableEventInit {
PushMessageDataInit
? data
= null;
Notification? notification
= null;
};
typedef (BufferSource or USVString) PushMessageDataInit
;
当 PushEvent
接口或继承自该接口的接口的 constructor
被调用时,标准事件构造步骤会扩展如下:
data
成员不存在,则将事件的 data
属性设为
null
,结束步骤。
data
" 成员 提取字节序列的结果。
data
属性设为新的 PushMessageData
实例,其 bytes 为 b。
data
属性必须返回初始化时的值。
notification
属性必须返回初始化时的值。
当用户代理从 推送服务 收到推送消息时, 必须执行以下步骤。
令 registration 为 subscription 的 关联 Service Worker 注册。
令 bytes 为 null。
如果推送消息包含负载:
如果 bytes 非 null:
令 baseURL 为 subscription 的 scope。
令 origin 为 baseURL 的 origin。
令 fallbackTimestamp 为 当前粗粒度墙上时间。
令 declarativeResult 为运行 声明式推送消息解析器, 参数为 bytes、origin、baseURL 和 fallbackTimestamp 的结果。
如果 declarativeResult 非失败:
令 notification 为 declarativeResult 的 notification。
设置 notification 的 Service Worker 注册 为 registration。
令 notificationShown 为 false。
如果 declarativeResult 的 mutable 为 true 且 registration 非 null:
令 result 为
触发 push 事件的结果,
参数为 registration、null 和一个表示 notification 的新的
Notification
对象。
如果 result 非失败,则将 notificationShown 设为 result 的 notification shown。
如果 notificationShown 为 false,则按 通知显示步骤, 参数为 notification。
如果 registration 为 null,则中止后续步骤。
令 data 为一个新的
PushMessageData
对象,
其 bytes
为 bytes(如果 bytes 非 null),否则为 null。
令 result 为 触发 push 事件的结果, 参数为 registration、data 和 null。
如果 result 为失败,且同一个 推送消息 已多次投递给 Service Worker 注册且均未成功, 则确认 推送消息。
push 事件结果是一个元组,包含一个notification shown(一个 布尔值)。
触发 push
事件,参数为 Service Worker 注册
registration、
PushMessageData
对象或 null data,
以及 notification 或 null
notification,步骤如下。返回失败或 push 事件结果。
令 notificationResult 为 null。
设置 registration 的 showNotification() 是否已成功调用 为 false。
使用 PushEvent
,在 registration 上
触发功能事件,事件名为
"push
",并设置如下属性:
data
notification
然后与 dispatchedEvent 并行执行:
等待 dispatchedEvent 的所有 延长生命周期 promise 都 resolve。
若未全部成功 resolve,则设置 notificationResult 为失败。
否则,设置 notificationResult 为 registration 的 showNotification() 是否已成功调用。
等待 notificationResult 非 null。
如果 notificationResult 为失败,则返回失败。
返回 (notificationResult)。
确认推送消息,参数为 pushMessage 表示按照 [RFC8030] 确认收到 pushMessage。
确认 推送消息会让 推送服务停止投递该消息,并向 应用服务器报告成功。这能防止 推送消息被 推送服务无限重试投递。
确认意味着 应用服务器可能错误地收到投递成功的回执。因此,在确认前应当允许多次拒绝,建议至少允许三次尝试。
pushsubscriptionchange 事件表示 推送订阅发生了应用无法控制的变更,例如被刷新、撤销或丢失。
触发 "pushsubscriptionchange
" 事件,参数为 Service Worker 注册
registration、newSubscription 和
oldSubscription,用户代理需要在 registration 上使用
PushSubscriptionChangeEvent
触发功能事件,
事件名为 "pushsubscriptionchange
",并设置如下属性:
newSubscription
oldSubscription
在将新的 推送订阅 的详细信息发送到你的 应用服务器时, 考虑使用更可靠的同步机制,如 [WEB-BACKGROUND-SYNC]。 用户可能受到不可靠的网络条件的影响,这可能导致获取失败。
WebIDL[Exposed=ServiceWorker, SecureContext]
interface PushSubscriptionChangeEvent
: ExtendableEvent {
constructor
(DOMString type, optional PushSubscriptionChangeEventInit
eventInitDict = {});
readonly attribute PushSubscription
? newSubscription
;
readonly attribute PushSubscription
? oldSubscription
;
};
newSubscription
属性,获取时,返回初始化时的值。
oldSubscription
属性,获取时,返回初始化时的值。
WebIDLdictionary PushSubscriptionChangeEventInit
: ExtendableEventInit {
PushSubscription
newSubscription
= null;
PushSubscription
oldSubscription
= null;
};
newSubscription
成员详细说明了每次调用
推送订阅时有效的
pushsubscriptionchange 事件。
当无法建立新的推送订阅时,该值将为
null
,例如,因为 Web 应用程序已失去明确许可。
oldSubscription
成员详细说明了不应再使用的
推送订阅。
当用户代理无法提供全套详细信息时,该值将为
null
,例如,由于部分数据库损坏。
推送 API 本身不提供任何方式来展示从 推送服务接收到的数据。相反,推送 API 依赖其他 API——主要是 通知 API 标准——来向最终用户展示收到的信息。因此,推送 API 本身没有可访问性要求。不过,[NOTIFICATIONS] 等规范对如何以无障碍方式展示通知提供了指导。
此外,呈现一个无障碍界面可能需要传递比推送消息所能承载的更多信息。推送消息更适合携带少量内容或标识符。如需传递较大的资源,则需要从服务器获取。
除了标记为非规范性的章节外,本规范中的所有编写指南、图示、示例和注释均为非规范性内容。规范中的其他内容均为规范性要求。
本文档中的关键词 MAY、MUST、MUST NOT、SHOULD 和 SHOULD NOT 应按照 BCP 14 [RFC2119] [RFC8174] 的说明进行解释,仅当它们以全大写形式出现时,才具有上述含义。
本规范定义了一套一致性标准,适用于单一产品:实现其中接口的 用户代理。
WebIDLdictionary PushPermissionDescriptor
: PermissionDescriptor {
boolean userVisibleOnly
= false;
};
[SecureContext]
interface mixin PushManagerAttribute
{
readonly attribute PushManager
pushManager
;
};
Window includes PushManagerAttribute
;
ServiceWorkerRegistration includes PushManagerAttribute
;
[Exposed=(Window,Worker), SecureContext]
interface PushManager
{
[SameObject] static readonly attribute FrozenArray<DOMString> supportedContentEncodings
;
Promise<PushSubscription
> subscribe
(optional PushSubscriptionOptionsInit
options = {});
Promise<PushSubscription
?> getSubscription
();
Promise<PermissionState> permissionState
(optional PushSubscriptionOptionsInit
options = {});
};
[Exposed=(Window,Worker), SecureContext]
interface PushSubscriptionOptions
{
readonly attribute boolean userVisibleOnly
;
[SameObject] readonly attribute ArrayBuffer? applicationServerKey
;
};
dictionary PushSubscriptionOptionsInit
{
boolean userVisibleOnly
= false;
(BufferSource or DOMString)? applicationServerKey
= null;
};
[Exposed=(Window,Worker), SecureContext]
interface PushSubscription
{
readonly attribute USVString endpoint
;
readonly attribute EpochTimeStamp? expirationTime
;
[SameObject] readonly attribute PushSubscriptionOptions
options
;
ArrayBuffer? getKey
(PushEncryptionKeyName
name);
Promise<boolean> unsubscribe
();
PushSubscriptionJSON
toJSON
();
};
dictionary PushSubscriptionJSON
{
USVString endpoint
;
EpochTimeStamp? expirationTime
= null;
record<DOMString, USVString> keys
;
};
enum PushEncryptionKeyName
{
"p256dh
",
"auth
"
};
[Exposed=ServiceWorker, SecureContext]
interface PushMessageData
{
ArrayBuffer arrayBuffer
();
Blob blob
();
Uint8Array bytes
();
any json
();
USVString text
();
};
[Exposed=ServiceWorker, SecureContext]
partial interface ServiceWorkerGlobalScope {
attribute EventHandler onpush
;
attribute EventHandler onpushsubscriptionchange
;
};
[Exposed=ServiceWorker, SecureContext]
interface PushEvent
: ExtendableEvent {
constructor
(DOMString type, optional PushEventInit
eventInitDict = {});
readonly attribute PushMessageData
? data
;
readonly attribute Notification? notification
;
};
dictionary PushEventInit
: ExtendableEventInit {
PushMessageDataInit
? data
= null;
Notification? notification
= null;
};
typedef (BufferSource or USVString) PushMessageDataInit
;
[Exposed=ServiceWorker, SecureContext]
interface PushSubscriptionChangeEvent
: ExtendableEvent {
constructor
(DOMString type, optional PushSubscriptionChangeEventInit
eventInitDict = {});
readonly attribute PushSubscription
? newSubscription
;
readonly attribute PushSubscription
? oldSubscription
;
};
dictionary PushSubscriptionChangeEventInit
: ExtendableEventInit {
PushSubscription
newSubscription
= null;
PushSubscription
oldSubscription
= null;
};
编辑们感谢 Mozilla 和 Telefónica Digital 团队实现 Firefox OS 推送消息解决方案,同时感谢下列在本文件中提供重要技术意见的人员:Antonio Amaya、Miguel García Arribas、Ben Bangert、Kit Cambridge、José Manuel Cantera、JR Conlin、Albert Crespell、Matt Gaunt、Phil Jenvey、Guillermo López、Nikhil Marathe、John Mellor、Pınar Özlen、Fernando R. Sela、Shijun Sun 和 Doug Turner。
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: