JS 監聽使用者頁面訪問&頁面關閉並進行資料上報操作

日升_rs發表於2024-05-24

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 進行可靠的資料傳輸

相關文章