前言
最近在做安全方面的項目,有個需求是在用戶訪問頁面和關(guān)閉頁面的時候,發(fā)送對應(yīng)的數(shù)據(jù)。
剛拿到需求的時候,覺得沒啥東西,init
的時候發(fā)送一次,頁面 unload
的時候發(fā)送一次就行了,很簡單,后面開發(fā)了一下,又根據(jù)當前項目,發(fā)現(xiàn)沒這么簡單
一、需求背景
1、項目需求
用戶在頁面訪問時發(fā)送數(shù)據(jù)到后臺,頁面關(guān)閉時也發(fā)送數(shù)據(jù)到后臺。
2、需求解析
很簡單的一句話
但是我們前面說了,沒有這么簡單,那是因為我們的項目比較復雜
項目是一個龐大的項目,內(nèi)部有好多子系統(tǒng),子系統(tǒng)是通過 iframe 內(nèi)嵌的
點擊 nav
模塊進入到子系統(tǒng),當前頁面的 hash
不會改變,只會改變 location.pathname
和 document.title
,但是這兩個改變有沒有事件監(jiān)聽到
點擊進入子系統(tǒng)時,也需要對之前的模塊進行關(guān)閉上報和當前模塊的訪問上報
iframe
內(nèi)嵌的項目不需要單獨上報,在 top
層進行上報即可
iframe
內(nèi)嵌的項目單獨通過 URL
訪問,則和當前項目一樣,需要訪問上報和關(guān)閉上報
3、需求概括
經(jīng)過分析,整體需求分為如下幾個點:
第一次進入頁面時觸發(fā)頁面訪問
刷新當前頁面時觸發(fā)頁面訪問
新 tab 進入頁面時觸發(fā)頁面訪問
當前頁面點擊 nav 進入其他模塊時,觸發(fā)頁面關(guān)閉&頁面訪問
關(guān)閉頁面時觸發(fā)頁面關(guān)閉
二、技術(shù)要點
主要包含以下幾點:
cookie
存儲
sessionStorage
存儲
addEventListener
事件監(jiān)聽
navigator.sendBeacon
數(shù)據(jù)發(fā)送
1、Cookie 存儲
使用 cookie
主要是因為項目的 domain
都一樣,存儲不同頁面的 title
、href
、referrer
等數(shù)據(jù)
【Cookie】
2、SessionStorage 存儲
這個主要是對在當前 tab
頁下的跳轉(zhuǎn)進行判斷,用來區(qū)分是否首次進入當前 tab
【SessionStorage】
3、addEventListener 事件監(jiān)聽
事件監(jiān)聽,注意是用來監(jiān)聽 unload
事件。
【addEventListener MDN】
4、navigator.sendBeacon 數(shù)據(jù)發(fā)送
這個我們后面在水一篇文章,單獨講講,本期只講用法
navigator.sendBeacon()
方法可用于通過 HTTP
POST
將少量數(shù)據(jù)異步傳輸?shù)?nbsp;Web
服務(wù)器。
4.1. 語法
navigator.sendBeacon(url);
navigator.sendBeacon(url, data);
4.2. 參數(shù)
4.2.1. url
url
參數(shù)表明 data
將要被發(fā)送到的網(wǎng)絡(luò)地址。
4.2.2. data 可選
data
參數(shù)是將要發(fā)送的 ArrayBuffer
、ArrayBufferView
、Blob
、DOMString
、FormData
或 URLSearchParams
類型的數(shù)據(jù)。
4.3. 返回值
當用戶代理成功把數(shù)據(jù)加入傳輸隊列時,sendBeacon()
方法將會返回 true
,否則返回 false
。
【navigator.sendBeacon】
三、需求實現(xiàn)
1、實現(xiàn)思路
1.1. 第一次進入頁面
無 session
無 cookie
調(diào)用 urlDetectChange
函數(shù)
觸發(fā) openPage()
進行頁面訪問上報
設(shè)置 session
字段
setTimeout
輪詢,設(shè)置 cookie
字段,監(jiān)聽 URL
變化
1.2. 刷新當前頁面
有 session
有 cookie
觸發(fā)頁面訪問上報
setTimeout
輪詢,監(jiān)聽 URL
變化
1.3. 點擊 nav 進入其他模塊
有 session
有 cookie
setTimeout
輪詢,當前 document
中的 title
和 href
與 cookie
中的不一致時,進行之前頁面關(guān)閉上報和當前頁面訪問上報
設(shè)置新的 cookie
值
繼續(xù) setTimeout
輪詢,監(jiān)聽 URL
變化
1.4. 新 tab 進入頁面
有 cookie
無 session
觸發(fā)頁面訪問上報
設(shè)置新的 cookie
繼續(xù) setTimeout
輪詢,監(jiān)聽 URL
變化
1.5. 關(guān)閉 tab
- 觸發(fā)
unload
監(jiān)聽事件 - 進行頁面關(guān)閉上報
2、頁面訪問->頁面關(guān)閉流程圖

3、頁面訪問&頁面關(guān)閉數(shù)據(jù)上報流程圖

4、數(shù)據(jù)上報
/**
* 上報接口
* @param {object} data 上報接口參數(shù)
* @returns {boolean} sendBeacon 接口返回信息
*/
export const sendBeaconMessage = (data: object): boolean =>
window.navigator.sendBeacon(
'xxx',
JSON.stringify(data)
)
5、設(shè)置 cookie 的值
// Cookies 使用 js-cookie
/**
* 設(shè)置 cookie 值
* 設(shè)置 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、頁面訪問發(fā)送消息
/**
* 頁面訪問發(fā)送消息
* @param {object} data 上報接口參數(shù)
* 設(shè)置 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、頁面關(guān)閉發(fā)送消息
/**
* 頁面關(guān)閉發(fā)送消息
* @param {object} data 上報接口參數(shù)
*/
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 改變進行監(jiān)聽&頁面關(guān)閉監(jiān)聽
/**
* 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 內(nèi)部的項目不進行監(jiān)聽,只在 top 層進行數(shù)據(jù)上報
if (window.top === window.self) {
// 頁面訪問上報 刷新頁面
sessionStorage.getItem('ACCESS_CLOSE_SESSION_NAME') && openPageSendBeacon({})
urlDetectChange()
window.addEventListener('unload', () => closePageSendBeacon({}))
}
四、總結(jié)
- 頁面訪問&頁面關(guān)閉數(shù)據(jù)上報能清楚的掌握用戶的使用數(shù)據(jù),對營銷活動或者畫像分析很有幫助
- 整體沒有難點,就是不同項目不同分析
- 如果你的項目是
hash
改變,那就可以針對 hash
進行監(jiān)聽 - 主要就是使用
navigator.sendBeacon
進行可靠的數(shù)據(jù)傳輸
轉(zhuǎn)自https://www.cnblogs.com/risheng/p/18209237
該文章在 2025/10/14 10:03:03 編輯過