Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang). W3C liability, trademark and permissive document license rules apply.
本规范定义了一个接口,Web开发者可以使用它来安排异步且非阻塞的数据传递,从而最大程度减少与其他关键操作的资源竞争,同时确保这些请求仍能被处理并送达目标。
本节描述了本文档在发布时的状态。当前 W3C 出版物及该技术报告的最新修订版可在 W3C 技术报告索引 https://www.w3.org/TR/ 查询。
本文档由 Web 性能工作组 作为 推荐轨道下的候选推荐草案发布,详情见 推荐流程。
作为候选推荐发布并不代表 W3C 及其会员的认可。候选推荐草案整合了工作组打算在后续候选推荐快照中包含的前一版候选推荐的变更。
本文档为草案,可能随时更新、替换或废止。将本文档作为正在进行的工作之外的内容进行引用是不合适的。
本文档由一个 在 W3C 专利政策 下运作的团体产生。 W3C 维护着 相关专利公开的公开列表 ,该页面还包括专利披露的说明。个人如果确实知晓某项专利且认为其包含 必要声明 ,必须按照 W3C 专利政策第六节 披露相关信息。
本文档受 2021年11月2日 W3C 流程文件 管理。
本节为非规范性内容。
Web 应用通常需要向一个或多个服务器发起请求,用于上报事件、状态更新和分析。这些请求通常不需要客户端处理响应(例如返回 204 或 200 HTTP 响应码且响应体为空),并且不应与其他高优先级操作(如抓取关键资源、响应输入、运行动画等)争夺网络和计算资源。然而,这种单向请求(信标)也负责传递关键的应用和度量数据,导致开发者不得不用高成本的方法来确保其成功送达:
上述送达与处理需求的不匹配,让大多数开发者面临艰难选择,并普遍采用损害用户体验的阻塞技术。本规范定义了一个接口,Web 开发者可以用其安排异步且非阻塞的数据传递,最大限度减少与其他关键操作的资源竞争,同时确保这些请求仍能被处理并送达目标:
以下示例展示了如何使用 sendBeacon()
方法来发送事件、点击和分析数据:
<html>
<script>
// 发送非阻塞信标以记录客户端事件
function reportEvent(event) {
var data = JSON.stringify({
event: event,
time: performance.now()
});
navigator.sendBeacon('/collector', data);
}
// 页面进入后台状态时,发送会话分析信标(Page Visibility API)
document.addEventListener('visibilitychange', function() {
if (document.visibilityState === 'hidden') {
var sessionData = buildSessionReport();
navigator.sendBeacon('/collector', sessionData);
}
});
</script>
<body>
<a href='http://www.w3.org/' onclick='reportEvent(this)'>
<button onclick="reportEvent('some event')">点击我</button>
</body>
</html>
上述示例使用了 visibilitychange
事件(定义见 [PAGE-VISIBILITY-2])来触发会话数据的发送。
该事件是页面进入后台状态(如用户切换应用、返回主屏幕等)或页面被卸载时在移动设备上唯一保证触发的事件。
开发者应避免依赖 unload 事件,因为当页面处于后台状态(即
visibilityState
等于 hidden
且进程被移动操作系统终止时,
unload 事件不会触发。
通过 sendBeacon()
方法发起的请求不会阻塞或与关键任务竞争,用户代理可优先处理提高网络效率,无需使用阻塞操作确保信标数据送达。
sendBeacon()
不具备且不打算解决的问题:
sendBeacon()
方法不提供离线存储或发送的特殊处理。信标请求与其他请求一样,可结合 [SERVICE-WORKERS] 实现必要的离线功能。
sendBeacon()
方法不用于后台同步或传输。用户代理限制最大接收负载大小,以确保信标请求能快速及时完成。
sendBeacon()
方法不支持自定义请求方法、请求头或更改其他请求和响应的
处理属性。如需定制请求设置,应使用 [FETCH] API,并将 keepalive 设置为
true
。
除标记为非规范性部分外,本规范中的所有创作指南、图示、示例和注释均为非规范性内容。除此之外,规范中的其它内容均为规范性内容。
本文档中的关键字 MAY(可选)、MUST(必须)、SHOULD(应该)、SHOULD NOT(不应该), 应按照 BCP 14 [RFC2119] [RFC8174] 的说明进行解释,仅当这些词以全部大写形式出现时,如本例所示,才按此解释。
为了便于阅读,本规范中这些关键字未全部使用大写字母。
在算法部分以命令式措辞表达的要求(如“去除所有前导空格字符”或“返回false并中止这些步骤”),应根据引入算法时所用关键字(“must”、“should”、“may”等)来解释其含义。
部分一致性要求以属性、方法或对象为对象提出。此类要求应解释为针对用户代理的要求。
以算法或具体步骤形式表述的一致性要求可以通过任何方式实现,只要最终结果是等价的。(特别地,本规范定义的算法旨在易于理解,并非为了高性能实现。)
WebIDL
sendBeacon()
方法会将
参数提供的数据发送到 data
url
参数指定的 URL:
visibilityState
状态转换为
hidden
时,用户代理 必须 立即调度所有信标请求的发送,并允许这些请求运行至完成,不阻塞其他关键和高优先级工作。
204 No Content
)。
sendBeacon()
方法如果用户代理能够成功将数据排队待传输,则返回
true,否则返回 false。
用户代理会限制通过此API发送的数据量:这有助于确保请求能成功送达且对用户和浏览器活动影响最小。如果待排队的 data 超过用户代理限制(详见 HTTP-network-or-cache
fetch),则本方法返回 false
;返回值为 true
表示浏览器已将数据排队待传输。但由于实际数据传输是异步进行的,该方法不会告知数据传输是否最终成功。
调用 sendBeacon()
方法并传入 url 和可选
data 参数时,需执行以下步骤:
将 base 设为 this 的 相关设置对象的 API 基础 URL。
将 parsedUrl 设为使用 url 和 base 运行 URL 解析器
的结果。如果算法返回错误,或 parsedUrl 的 scheme 不是
"http" 或 "https",则 抛出
"
"
异常并终止这些步骤。TypeError
no-cors
"。如果 data 不为 null
:
false
,并终止这些步骤。
通过 Beacon API 发起的请求会自动设置 keepalive 标志,开发者也可在使用 Fetch API 时手动设置。所有设置了此标志的请求会共享 Fetch API 内部强制执行的在途配额限制。
cors
"。Content-Type
值,则将 corsMode 设为 "no-cors
"。
Content-Type
头。
true
,返回 sendBeacon()
调用,并继续并行执行以下步骤:
sendBeacon()
接口提供了异步且非阻塞的数据传递机制。此API可以用于:
传递的数据可能包含敏感信息,例如用户在网页上的活动数据,发送到服务器。虽然这可能带来用户隐私风险,现有方法(如脚本表单提交、图片信标和XHR/fetch请求)也具备类似能力,但存在各种性能折衷:这些请求可能被用户代理中止,除非开发者阻止用户代理处理其他事件(例如发起同步请求或使用空循环等待),且用户代理无法对这些请求进行优先级调度和合并,以优化系统资源使用。
由 sendBeacon()
发起的请求具有以下属性:
Content-Type
是 CORS安全列表请求头,则请求模式为
no-cors
——分别类似于图片信标或表单提交。
Access-Control-Allow-Credentials
,
Access-Control-Allow-Origin
,
Access-Control-Allow-Headers
.
因此,从安全角度看,Beacon API 遵循开发者当前所用方法的安全策略。同样,从隐私角度看,最终请求会在API调用时或页面可见性变化时立即发起,这限制了暴露的信息(如用户IP地址)仅限于开发者可访问的现有生命周期事件。不过,用户代理可能考虑采用其他方法将此类请求展示给用户,以提高透明度。
相比其他方案,sendBeacon()
API有两点限制:不提供回调方法,负载大小可由用户代理限制。除此之外,sendBeacon()
API不受额外限制。用户代理不应跳过或限制对sendBeacon()
的处理,因为它可能包含关键应用状态、事件和分析数据。同样,用户代理在“隐私浏览”或类似模式下也不应禁用sendBeacon()
,既可避免破坏应用,又可防止暴露用户处于此模式。
感谢 Alois Reitbauer、Arvind Jain、Anne van Kesteren、Boris Zbarsky、Chase Douglas、Daniel Austin、Jatinder Mann、James Simonsen、Jason Weber、Jonas Sicking、Nick Doty、Philippe Le Hegaret、Todd Reifsteck、Tony Gentilcore、William Chan 和 Yoav Weiss 对本工作的贡献。