用戶在頁面訪問時發送數據到後臺,頁面關閉時也發送數據到後臺。 第一次進入頁面時觸發頁面訪問 刷新當前頁面時觸發頁面訪問 新 tab 進入頁面時觸發頁面訪問 當前頁面點擊 nav 進入其他模塊時,觸發頁面關閉&頁面訪問 關閉頁面時觸發頁面關閉 ...
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
等數據
2、SessionStorage 存儲
這個主要是對在當前 tab
頁下的跳轉進行判斷,用來區分是否首次進入當前 tab
3、addEventListener 事件監聽
事件監聽,註意是用來監聽 unload
事件。
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
。
三、需求實現
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
進行可靠的數據傳輸