Web Tracking 前端埋点技术探究
本文最后更新于:2022年7月26日 上午
介绍
Web Tracking(此处细分来说应该叫 Web beacon)。Web beacon 是一种在网页和电子邮件上使用的技术,可以不显眼地(通常是无形的)检查用户是否访问了某些内容。Web beacon 通常由第三方用于监控用户在网站上的活动,以进行网络分析或页面标记。它们也可用于电子邮件跟踪。当使用JavaScript实现时,它们可以被称为JavaScript标签。
使用此类信标,公司和组织可以跟踪网络用户的在线行为。起初,进行此类跟踪的公司主要是广告商或网络分析公司;后来的社交媒体网站也开始使用这种跟踪技术,例如通过使用充当跟踪信标的按钮。
2017年,W3C发布了Web开发人员可用于创建Web信标的接口的候选规范。
使用
<img>
例如如果我们发送邮件后,想知道对方是否已读,就需要在邮件中嵌入一张图片,我们发送的get请求即是图片的src。当我们收到这次get请求后,在接口中写下逻辑处理函数等,处理完毕需要返回一张图片(通常情况下是一张1x1的GIF图片)。
例如嵌入在 HTML 中:
1 |
|
又或者嵌入到 JavaScript 中:
1 |
|
上面的 http://api.toflying.com/report?from=test&id=123
就是API GET请求的URL,当然真实情况下是不存在的。我们可以携带任意参数(例如来源的平台、当前文章的ID等),并可以在后端处理相应逻辑。
那么问题来了,为什么要用 <img>
标签?
那是因为,我们的 <img>
相当于一次 GET 请求,并且没有跨域的限制。正是因为没有跨域限制,所以我们可以在任意网站(或者在我们发送的邮件中)嵌入该标签。这样我们就可以知道这些网站页面或者邮件被人阅读的情况,甚至可以分析对方的设备、IP、意图等等。
那为什么一定要返回一张图片?
如果我们返回的是一段文本或者说是JSON字符串(返回头中的 content-type: application/json;)。<img>
标签会触发 onerror 事件,会报错。如果返回空的话也会报CORB的问题,然后页面上的那张图片也会裂开(如果标签存在的话)。所以我们通常返回一张图片(返回头为content-type: image/*)。
为什么图片是 1x1 GIF 图片?
在同样尺寸下,不同格式的图片GIF格式占用的存储空间是最小的,也可以降低服务器的传输压力。
navigator.sendBeacon
navigator.sendBeacon()
方法可用于通过 HTTP POST 将少量数据 异步 传输到 Web 服务器。它主要用于将统计数据发送到 Web 服务器,同时避免了用传统技术(如:XMLHttpRequest)发送分析数据的一些问题。
1 |
|
其中:url 是 POST 请求的地址。而 data 可选,是请求附带的数据( ArrayBuffer、ArrayBufferView、Blob、DOMString、FormData 或 URLSearchParams)
当用户代理成功把数据加入传输队列时,sendBeacon()
方法将会返回 true
,否则返回 false
。
相较于图片的src,这种方式的更有优势:
- 不会和主要业务代码抢占资源,而是在浏览器空闲时去做发送;
- 并且在页面卸载时也能保证请求成功发送,不阻塞页面刷新和跳转;
现在的埋点监控工具通常会优先使用sendBeacon,但由于浏览器兼容性,还是需要用图片的src兜底。
用法如下:
1 |
|
当然,在实际使用中也没有这么简单。
过去,许多网站使用 unload
或 beforeunload
事件以在会话结束时发送统计数据。然而这是不可靠的,在许多情况下(尤其是移动设备)浏览器不会产生 unload
、beforeunload
或 pagehide
事件。下面列出了一种不触发上述事件的情况:
- 用户加载了网页并与其交互。
- 完成浏览后,用户切换到了其它应用程序,而不是关闭选项卡。
- 随后,用户通过手机的应用管理器关闭了浏览器应用。
此外,unload
事件与现代浏览器实现的往返缓存(bfcache)不兼容。在部分浏览器(如:Firefox)通过在 bfcache 中排除包含 unload
事件处理器的页面来解决不兼容问题,但这存在性能损失。
其它浏览器,例如 Safari 和 Android 上的 Chrome 浏览器则采取用户在同一标签页下导航至其它页面时不触发 unload
事件的方法来解决不兼容问题。
Firefox 也会在 bfcache 中排除包含 beforeunload
事件处理器的页面。
在会话结束时发送统计数据
网站通常希望在用户完成页面浏览后向服务器发送分析或诊断数据,最可靠的方法是在 visibilitychange
事件发生时发送数据:
1 |
|
可使用 pagehide
件来代替部分浏览器未实现的 visibilitychange
事件。和 beforeunload
与 unload
事件类似,这一事件不会被可靠地触发(特别是在移动设备上),但它与 bfcache
兼容。
浏览器兼容性
总结
通常 <img>
标签出现的需要跨域的场景中。而 navigator.sendBeacon
可以在自己网站使用,当然如果使用不了(例如IE浏览器)可以用 <img>
。
未完待续