JS 监听用户页面访问&页面关闭操作并进行数据上报

简介: 该文主要讨论了一个网页安全项目的需求和实现,涉及用户访问和离开页面时的数据报告。需求包括首次进入、刷新、新标签页打开、导航切换以及页面关闭时的数据发送。技术要点包括使用Cookie和SessionStorage存储信息,事件监听以及navigator.sendBeacon方法进行数据发送。实现策略包括轮询检测URL变化和在unload事件中触发页面关闭报告。文章还提到了相关流程图和代码示例,总结中强调了数据上报在用户行为分析中的重要性。

前言

最近在做安全方面的项目,有个需求是在用户访问页面和关闭页面的时候,发送对应的数据。

刚拿到需求的时候,觉得没啥东西,init 的时候发送一次,页面 unload 的时候发送一次就行了,很简单,后面开发了一下,又根据当前项目,发现没这么简单

一、需求背景

1、项目需求

用户在页面访问时发送数据到后台,页面关闭时也发送数据到后台。

2、需求解析

很简单的一句话

但是我们前面说了,没有这么简单,那是因为我们的项目比较复杂

  1. 项目是一个庞大的项目,内部有好多子系统,子系统是通过 iframe 内嵌的
  2. 点击 nav 模块进入到子系统,当前页面的 hash 不会改变,只会改变 location.pathnamedocument.title,但是这两个改变有没有事件监听到
  3. 点击进入子系统时,也需要对之前的模块进行关闭上报和当前模块的访问上报
  4. iframe 内嵌的项目不需要单独上报,在 top 层进行上报即可
  5. iframe 内嵌的项目单独通过 URL 访问,则和当前项目一样,需要访问上报和关闭上报

3、需求概括

经过分析,整体需求分为如下几个点:

  1. 第一次进入页面时触发页面访问
  2. 刷新当前页面时触发页面访问
  3. 新 tab 进入页面时触发页面访问
  4. 当前页面点击 nav 进入其他模块时,触发页面关闭&页面访问
  5. 关闭页面时触发页面关闭

二、技术要点

主要包含以下几点:

  1. cookie 存储
  2. sessionStorage 存储
  3. addEventListener 事件监听
  4. navigator.sendBeacon 数据发送

1、Cookie 存储

使用 cookie 主要是因为项目的 domain 都一样,存储不同页面的 titlehrefreferrer 等数据

【Cookie】

2、SessionStorage 存储

这个主要是对在当前 tab 页下的跳转进行判断,用来区分是否首次进入当前 tab

【SessionStorage】

3、addEventListener 事件监听

事件监听,注意是用来监听 unload 事件。

【addEventListener MDN】

4、navigator.sendBeacon 数据发送

这个我们后面在水一篇文章,单独讲讲,本期只讲用法

navigator.sendBeacon() 方法可用于通过 HTTP POST 将少量数据异步传输到 Web 服务器。

4.1. 语法

navigator.sendBeacon(url);
navigator.sendBeacon(url, data);

4.2. 参数

4.2.1. url

url 参数表明 data 将要被发送到的网络地址。

4.2.2. data 可选

data 参数是将要发送的 ArrayBufferArrayBufferViewBlobDOMStringFormDataURLSearchParams 类型的数据。

4.3. 返回值

当用户代理成功把数据加入传输队列时,sendBeacon() 方法将会返回 true,否则返回 false

【navigator.sendBeacon】

三、需求实现

1、实现思路

1.1. 第一次进入页面

  1. sessioncookie
  2. 调用 urlDetectChange 函数
  3. 触发 openPage() 进行页面访问上报
  4. 设置 session 字段
  5. setTimeout 轮询,设置 cookie 字段,监听 URL 变化

1.2. 刷新当前页面

  1. sessioncookie
  2. 触发页面访问上报
  3. setTimeout 轮询,监听 URL 变化

1.3. 点击 nav 进入其他模块

  1. sessioncookie
  2. setTimeout 轮询,当前 document 中的 titlehrefcookie 中的不一致时,进行之前页面关闭上报和当前页面访问上报
  3. 设置新的 cookie
  4. 继续 setTimeout 轮询,监听 URL 变化

1.4. 新 tab 进入页面

  1. cookiesession
  2. 触发页面访问上报
  3. 设置新的 cookie
  4. 继续 setTimeout 轮询,监听 URL 变化

1.5. 关闭 tab

  1. 触发 unload 监听事件
  2. 进行页面关闭上报

2、页面访问->页面关闭流程图

3、页面访问&页面关闭数据上报流程图

4、数据上报

/**
* 上报接口
* @param {object} data 上报接口参数
* @returns {boolean} sendBeacon 接口返回信息
*/
export const sendBeaconMessage = (data: object): boolean =>
  window.navigator.sendBeacon(
    'xxx',
    JSON.stringify(data)
  )

5、设置 cookie 的值

// Cookies 使用 js-cookie
/**
 * 设置 cookie 值
 * 设置 href、pageTitle、referrer 字段
 * key 为 ACCESS_CLOSE_COOKIE_NAME
 * domain 为 '.xxx.com'
 */
export const setAccessPageCookie = () =>
  Cookies.set(
    'ACCESS_CLOSE_COOKIE_NAME',
    JSON.stringify({
      href: location.href,
      pageTitle: document.title,
      referrer: document.referrer
    }),
    { domain: '.xxx.com', expires: 30 }
  )

6、页面访问发送消息

/**
 * 页面访问发送消息
 * @param {object} data 上报接口参数
 * 设置 sessionStorage 的值,
 */
export const openPageSendBeacon = async (data: object) => {
  sessionStorage.setItem('ACCESS_CLOSE_SESSION_NAME', 'ISTRUE')
  const sendBeaconSusscess = sendBeaconMessage(data)
  // 打印 sendBeaconSusscess 的值
  console.log(
    '%c client:sendDataToRemote use sendBeacon access page: %o',
    'color: green;',
    sendBeaconSusscess
  )
}

7、页面关闭发送消息

/**
 * 页面关闭发送消息
 * @param {object} data 上报接口参数
 */
export const closePageSendBeacon = async (data: object) => {
  const sendBeaconSusscess = sendBeaconMessage(data)
  // 打印 sendBeaconSusscess 的值
  console.log(
    '%c client:sendDataToRemote use sendBeacon close page: %o, ',
    'color: red;',
    sendBeaconSusscess
  )
}

8、URL 改变进行监听&页面关闭监听

/**
 * URL 改变事件
 */
export const urlDetectChange = () => {
  const accessPageData = Cookies.get('ACCESS_CLOSE_COOKIE_NAME')
    ? JSON.parse(Cookies.get('ACCESS_CLOSE_COOKIE_NAME'))
    : null
  const sessionAccessData = sessionStorage.getItem('ACCESS_CLOSE_SESSION_NAME')
  // 第一次进入页面 和 新 tab 进入页面
  if (!accessPageData || !sessionAccessData) {
    openPageSendBeacon({})
  }
  setTimeout(() => {
    if (
      accessPageData &&
      location.href !== accessPageData.href &&
      document.title !== accessPageData.pageTitle &&
      sessionAccessData
    ) {
      // 点击 nav 进入其他模块
      closePageSendBeacon({})
      openPageSendBeacon({})
    }
    setAccessPageCookie()
    urlDetectChange()
  }, 1000)
}
// 加这个是针对 iframe 内部的项目不进行监听,只在 top 层进行数据上报
if (window.top === window.self) {
  // 页面访问上报 刷新页面
  sessionStorage.getItem('ACCESS_CLOSE_SESSION_NAME') && openPageSendBeacon({})
  urlDetectChange()
  window.addEventListener('unload', () => closePageSendBeacon({}))
}

四、总结

  1. 页面访问&页面关闭数据上报能清楚的掌握用户的使用数据,对营销活动或者画像分析很有帮助
  2. 整体没有难点,就是不同项目不同分析
  3. 如果你的项目是 hash 改变,那就可以针对 hash 进行监听
  4. 主要就是使用 navigator.sendBeacon 进行可靠的数据传输
相关文章
|
2月前
|
编解码 前端开发 JavaScript
js react antd 实现页面低分变率和高分变率下字体大小自适用,主要是配置antd
在React中结合Ant Design与媒体查询,通过less变量和响应式断点动态调整`@font-size-base`,实现多分辨率下字体自适应,提升跨设备体验。
117 2
|
6月前
|
Web App开发 数据采集 JavaScript
动态网页爬取:Python如何获取JS加载的数据?
动态网页爬取:Python如何获取JS加载的数据?
1113 58
|
9月前
|
数据采集 JavaScript Android开发
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
388 7
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
|
8月前
|
JavaScript 前端开发 API
纯js轻量级页面顶部Loading进度条插件
纯js轻量级页面顶部Loading进度条插件
|
8月前
|
数据采集 JavaScript 前端开发
JavaScript中通过array.filter()实现数组的数据筛选、数据清洗和链式调用,JS中数组过滤器的使用详解(附实际应用代码)
用array.filter()来实现数据筛选、数据清洗和链式调用,相对于for循环更加清晰,语义化强,能显著提升代码的可读性和可维护性。博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
280 2
|
12月前
|
JavaScript 前端开发
JavaScript中的原型 保姆级文章一文搞懂
本文详细解析了JavaScript中的原型概念,从构造函数、原型对象、`__proto__`属性、`constructor`属性到原型链,层层递进地解释了JavaScript如何通过原型实现继承机制。适合初学者深入理解JS面向对象编程的核心原理。
212 1
JavaScript中的原型 保姆级文章一文搞懂
|
12月前
JS+CSS3文章内容背景黑白切换源码
JS+CSS3文章内容背景黑白切换源码是一款基于JS+CSS3制作的简单网页文章文字内容背景颜色黑白切换效果。
135 0