sendBeacon
一、认识
navigator.sendBeacon()
方法可用于通过 HTTP POST
将少量数据异步传输到 Web
服务器。它主要用于将统计数据发送到 Web
服务器,同时避免了用传统技术(如:XMLHttpRequest
)发送分析数据的一些问题。
navigator.sendBeacon
通过 HTTP POST
发送的请求不会在浏览器中的 Network
出现,但是服务端确实可以接收到的。
二、对比
2.1 sendBeacon vs IMG
我们可以以向服务端请求图片资源的形式,像服务端传输少量数据,这种方式不会造成跨域。但是 Image
是以 GET
方式请求图片资源的方式,将上报数据附在 URL
上携带到服务端,而 URL
地址的长度是有一定限制的。规范对 URL
长度并没有要求,但是浏览器、服务器、代理服务器都对 URL
长度有要求。有的浏览器要求URL
中path
部分不超过 2048
,这就导致有些请求会发送不完全。
而 navigator.sendBeacon
是以 HTTP POST
的方式异步上传数据, 相比 HTTP GET
可以传输更多的数据。
2.1 sendBeacon vs XMLHttpRequest & IMG
过去,为了上报埋点数据, 通常是:
-
IMG
-
XMLHttpRequest
上述的所有方法都会迫使用户代理延迟卸载文档,并使得下一个导航出现的更晚。下一个页面对于这种较差的载入表现无能为力。
这就是 sendBeacon()
方法存在的意义。使用 sendBeacon()
方法会使用户代理在有机会时异步地向服务器发送数据,同时不会延迟页面的卸载或影响下一导航的载入性能。这意味着:
-
数据发送是可靠的
-
数据异步传输
-
不影响下一导航的载入
2.43 sendBeacon report schema summarize
navigator.sendBeacon
会在合适的时机通过 HTTP POST
将少量数据异步发送到服务端, 不会阻塞当前页面的卸载, 也不会阻塞下个新页面的加载, 不存在性能问题, 这意味着 navigator.sendBeacon
在可靠、异步发送数据的同时, 不会影响当前页面、下一个页面。
三、语法
3.1 点击事件上报
- javascript
- html
function buryingPointBySendBeacon(type) {
const params = JSON.stringify({
type,
url: "sendBeacon",
device: "pc",
});
const result = navigator.sendBeacon(
"/server/buryingPoint/sendBeacon",
params
);
console.log(result);
}
const buttonSendBeacon = document.querySelector("#button-sendBeacon");
buttonSendBeacon.addEventListener("click", function () {
buryingPointBySendBeacon("sendBeacon");
});
<button id="button-sendBeacon">SendBeacon 埋点</button>
3.2 会话结束上报
网站通常希望在用户完成页面浏览后向服务器发送分析或诊断数据,最可靠的方法是在 visibilitychange
事件发生时发送数据。我们应该避免使用 unload
和 beforeunload
事件以在会话结束时发送统计数据。然而这是不可靠的,在许多情况下(尤其是移动设备)浏览器不会产生 unload
、beforeunload
或 pagehide
事件。下面列出了一种不触发上述事件的情况:
-
用户加载了网页并与其交互
-
完成浏览后,用户切换到了其他应用程序,而不是关闭选项卡
-
随后,用户通过手机的应用管理器关闭了浏览器应用
此外,unload
事件与现代浏览器实现的往返缓存(bfcache
)不兼容。在部分浏览器(如:Firefox
)通过在 bfcache
中排除包含 unload
事件处理器的页面来解决不兼容问题,但这存在性能损失。其他浏览器,例如 Safari
和 Android
上的 Chrome
浏览器则采取用户在同一标签页下导航至其他页面时不触发 unload
事件的方法来解决不兼容问题。Firefox
也会在 bfcache
中排除包含 beforeunload
事件处理器的页面。
综上所述: 我们如果在会话结束后上报数据,应该使用 visibilitychange
事件发送数据。如果 visibilitychange
在某个浏览器未实现, 可以优雅降级为 pagehide
, 和 beforeunload
与 unload
事件类似,pagehide
这一事件不会被可靠地触发(特别是在移动设备上),但它与 bfcache
兼容。
function buryingPointBySendBeacon(type) {
const params = JSON.stringify({
type,
url: "sendBeacon",
device: "pc",
});
const result = navigator.sendBeacon(
"/server/buryingPoint/sendBeacon",
params
);
console.log(result);
}
function handleVisibilitychange() {
if (document.visibilityState === "hidden") {
buryingPointBySendBeacon();
}
}
document.addEventListener("visibilitychange", handleVisibilitychange);
四、请求
navigator.sendBeacon
发送的请求是 ping
类型, 所以只会在 Network
中的 All
或者 Other
里出现, 不会出现在 Fetch/XHR
列表中。如图所示: