JS 監聽使用者頁面訪問&頁面關閉操作並進行資料上報
前言
最近在做安全方面的專案,有個需求是在使用者訪問頁面和關閉頁面的時候,傳送對應的資料。
剛拿到需求的時候,覺得沒啥東西,init
的時候傳送一次,頁面 unload
的時候傳送一次就行了,很簡單,後面開發了一下,又根據當前專案,發現沒這麼簡單
一、需求背景
1、專案需求
使用者在頁面訪問時傳送資料到後臺,頁面關閉時也傳送資料到後臺。
2、需求解析
很簡單的一句話
但是我們前面說了,沒有這麼簡單,那是因為我們的專案比較複雜
-
專案是一個龐大的專案,內部有好多子系統,子系統是透過 iframe 內嵌的
-
點選
nav
模組進入到子系統,當前頁面的hash
不會改變,只會改變location.pathname
和document.title
,但是這兩個改變有沒有事件監聽到 -
點選進入子系統時,也需要對之前的模組進行關閉上報和當前模組的訪問上報
-
iframe
內嵌的專案不需要單獨上報,在top
層進行上報即可 -
iframe
內嵌的專案單獨透過URL
訪問,則和當前專案一樣,需要訪問上報和關閉上報
3、需求概括
經過分析,整體需求分為如下幾個點:
-
第一次進入頁面時觸發頁面訪問
-
重新整理當前頁面時觸發頁面訪問
-
新 tab 進入頁面時觸發頁面訪問
-
當前頁面點選 nav 進入其他模組時,觸發頁面關閉&頁面訪問
-
關閉頁面時觸發頁面關閉
二、技術要點
主要包含以下幾點:
-
cookie
儲存 -
sessionStorage
儲存 -
addEventListener
事件監聽 -
navigator.sendBeacon
資料傳送
1、Cookie 儲存
使用 cookie
主要是因為專案的 domain
都一樣,儲存不同頁面的 title
、href
、referrer
等資料
【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
引數是將要傳送的 ArrayBuffer
、ArrayBufferView
、Blob
、DOMString
、FormData
或 URLSearchParams
型別的資料。
4.3. 返回值
當使用者代理成功把資料加入傳輸佇列時,sendBeacon()
方法將會返回 true
,否則返回 false
。
【navigator.sendBeacon】
三、需求實現
1、實現思路
1.1. 第一次進入頁面
-
無
session
無cookie
-
呼叫
urlDetectChange
函式 -
觸發
openPage()
進行頁面訪問上報 -
設定
session
欄位 -
setTimeout
輪詢,設定cookie
欄位,監聽URL
變化
1.2. 重新整理當前頁面
-
有
session
有cookie
-
觸發頁面訪問上報
-
setTimeout
輪詢,監聽URL
變化
1.3. 點選 nav 進入其他模組
-
有
session
有cookie
-
setTimeout
輪詢,當前document
中的title
和href
與cookie
中的不一致時,進行之前頁面關閉上報和當前頁面訪問上報 -
設定新的
cookie
值 -
繼續
setTimeout
輪詢,監聽URL
變化
1.4. 新 tab 進入頁面
-
有
cookie
無session
-
觸發頁面訪問上報
-
設定新的
cookie
-
繼續
setTimeout
輪詢,監聽URL
變化
1.5. 關閉 tab
- 觸發
unload
監聽事件 - 進行頁面關閉上報
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({}))
}
四、總結
- 頁面訪問&頁面關閉資料上報能清楚的掌握使用者的使用資料,對營銷活動或者畫像分析很有幫助
- 整體沒有難點,就是不同專案不同分析
- 如果你的專案是
hash
改變,那就可以針對hash
進行監聽 - 主要就是使用
navigator.sendBeacon
進行可靠的資料傳輸