首页 > 其他分享 >JS 监听用户页面访问&页面关闭并进行数据上报操作

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

时间:2024-05-24 10:08:36浏览次数:22  
标签:JS 访问 cookie 上报 data 监听 页面

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

前言

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

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

一、需求背景

1、项目需求

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

2、需求解析

很简单的一句话

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

  1. 项目是一个庞大的项目,内部有好多子系统,子系统是通过 iframe 内嵌的

  2. 点击 nav 模块进入到子系统,当前页面的 hash 不会改变,只会改变 location.pathname document.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、页面访问->页面关闭流程图

image

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

image

4、数据上报

/**
* 上报接口
* @param {object} data 上报接口参数
* @returns {boolean} sendBeacon 接口返回信息
*/
export const sendBeaconMessage = (data: object): boolean =>
  window.navigator.sendBeacon(
    'xxx',
    JSON.stringify(data)
  )
// 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 进行可靠的数据传输

标签:JS,访问,cookie,上报,data,监听,页面
From: https://www.cnblogs.com/risheng/p/18209237

相关文章

  • React后台管理(八)-- 开发页面前准备---插槽以及函数组件传值
    文章目录前言一、插槽的使用1.父组件结构如下2.子组件接受插槽内容二、父子函数组件传值1.父组件传值给子组件(1)父组件定义属性传值给子组件(2)子组件通过props去接收属性值2.子组件传值父组件(1)父组件接收子组件的值,更新数据(2)子组件通过方法,将值传出给父组件,类似vue的......
  • 基于three.js的Instanced Draw+LOD+Frustum Cull的改进实现
    大家好,本文在上文的基础上,优化了InstancedDraw+LOD+FrustumCull的性能,性能提升了3倍以上关键词:three.js、InstancedDraw、大场景、LOD、FrustumCull、优化、Web3D、WebGL、开源上文:three.js使用InstancedDraw+FrustumCull+LOD来渲染大场景(开源)相对于上文的改进点相对于......
  • html+css+js
    HTMLHTML标题代码效果HTML段落代码效果HTML超链接代码效果HTML图像代码效果HTML文本格式化代码效果HTML头部代码效果HTML表格代码效果HTML布局代码效果......
  • 微信小程序中页面显示时触发子组件的重新渲染
    使用生命周期函数:在页面的onShow或onLoad生命周期函数中,调用子组件的方法或者改变子组件的数据,从而触发子组件的重新渲染。例如,在页面的js文件中:Page({onShow:function(){//调用子组件的方法this.selectComponent('#childComponentId').refreshDa......
  • nodeJS文件操作
    const{log}=require("console");constfs=require("fs");constpath=require("path");constfilename=path.resolve(__dirname,"./myfiles1.txt");//console.log(filename)//fs.readFile(filename,(err,content)......
  • 多目标应用:基于NSGA2求解柔性作业车间调度问题(FJSP),MATLAB代码
    一、柔性作业车间调度问题柔性作业车间调度问题(FlexibleJobSchedulingProblem,FJSP)的描述如下:n个工件{J,J......
  • js逆向系列1.1、JavaScript基础语法
    JS逆向爬虫语法初阶dy:a_b,xhs:x-s等有需要联系。v:a2247429407【1】JavaScript初识JavaScript是一种用于在客户端(即用户的浏览器)上运行的编程语言。它是一种脚本语言,可以直接嵌入到HTML页面中,并由浏览器解释和执行。在客户端环境中,JavaScript可以与用户交互,操作和修......
  • 前端js面试题
    01.你能解释一下JavaScript中let和var的区别吗?答:“let”和“var”之间的主要区别是用“let”声明的变量具有块作用域,而用“var”声明的变量具有函数作用域。02.你能解释一下JavaScript中的闭包吗?答:闭包是一个函数,即使在父函数返回之后,它也可以访问其父作用域中的变量。......
  • nodeJS 内置对象
    //const{log}=require("console");//const{argv}=require("process");//log(__dirname)//setImmediate(()=>{//log(__filename)//})//constbuffer=Buffer.from('a1','utf-8')//log(buffer)/......
  • 类转词典 转json 序列化 魔术方法
      classTest:def__init__(self,totals,uniques,pre):self.totals=totalsself.uniques=uniquesself.cumulative_sum=totalsifpre:self.cumulative_sum+=pre.cumulative_sumpre=Test(......