hugh 的个人博客

Everyday is a new day

如何保证页面卸载时的上报数据完整性

监控系统重要的一环是数据上报。

为了减少请求的次数,我们把一些细粒度的收集信息压入到内存中,等待触发一定规则后上报后台。

一般的规则是, 等待 20s 或者 队列中的数据达到一定条数(如 10 条) 或者页面 unload 时!

定时和定量的操作是没有问题的, 可以使用 xhr 或者其它任何交互方式,都可以轻松完成, 并保证数据的完整性!

然而,页面 unload 时,坑就多了,

1. 使用异步 xhr

这是最先使用的方式, 在 Chrome 测试一切 ok。 但是线上运行一段时间,发现数据丢失的现象。基本可以确定是浏览器行为导致的 unload 未成功执行异步 xhr,

解决方案: 在 unload 时加一个循环等待, 或者创建一个 img 并指定 src, 通过资源加载的方式延迟关闭以保证异步请求正常发送

2. 异步不好使,试试同步 xhr

同步 xhr,在现代浏览器已经不提倡使用, 同时同步的操作也会阻塞浏览器的关闭, 如果是 reload,会造成用户体验问题, 并不是一个合适的解决方案, 但是可以作为备用

3. 杀手锏 sendBeacon

使用 **sendBeacon()**方法会使用户代理在有机会时异步地向服务器发送数据,同时不会延迟页面的卸载或影响下一导航的载入性能。这就解决了提交分析数据时的所有的问题:数据可靠,传输异步并且不会影响下一页面的加载。

BUT! 杀手锏毕竟是新玩意,对老古董还是没效的

注意点

Chrome 最新版本已不支持发送 application/json 格式的 blob 数据,会出现如下错误

Failed to execute 'sendBeacon' on 'Navigator': sendBeacon() with a Blob whose type is not any of the CORS-safelisted values for the Content-Type request header is disabled temporarily. See http://crbug.com/490015 for details.

可以改成使用以下三种

  • application/x-www-form-urlencoded

  • multipart/form-data

  • text/plain

4. 如果不追求时效性, 自然是使用缓存 + 延时发送的策略最优雅, 同时丢失数据的问题也可以大大改善

在 unload 或者 beforeunload 中,将数据写入 localstorage (caniuse), 下次加载之前检查下是否有需要发送的数据, 有的话拿出来发送并清除数据

使用 beacon demo 如下:

if(navigator && navigator.sendBeacon) {
                       var blob = new Blob([stringify(data)],
                               {type : 'text/plain'});
                       navigator.sendBeacon(this.endpoint, blob);
                   } else {
                       if(_window.XMLHttpRequest) {
                           var xhr = new XMLHttpRequest();
                           xhr.open("POST", this.endpoint, false);
                           xhr.setRequestHeader("content-type", "application/json")
                           xhr.send(stringify(data))
                       }
                   }

=========================

19.08.05 测试

方式: 定时 2min + 动态条数发送记录;sendBeacon+ 同步 AJAX 兼容处理; unload 超过 2s,放入到 localstorage;load 时加载 localstorage 补发

验证测试数据, 数据丢失率高达6%

可能原因:

  1. 由于合规问题,prod 会前端重定向域名,导致补发可能未成功

  2. 可能出现人为强制刷新,导致失败

  3. 原先认为该数据只做补充,未在发送出加返回校验

解决方式:

加请求强校验,后端加冗余数据过滤

待测试效果验证~

======


标题:如何保证页面卸载时的上报数据完整性
作者:hugh0524
地址:https://blog.uproject.cn/articles/2019/03/12/1552404978819.html

209 浏览