前端添加埋點四種方式和原理總結(jié)
前言
核心實現(xiàn)思路 埋點本質(zhì)上就是向埋點平臺的數(shù)據(jù)接收 URL 發(fā)送一個 HTTP 請求,請求中攜帶了格式化的數(shù)據(jù)(通常是 URL 參數(shù)或 JSON)。您提供的響應(yīng)頭表明這是一個 GET 請求,并且服務(wù)器配置為不緩存且允許跨域。
方法一:使用 Image Beacon(最經(jīng)典、最可靠的方法)
這是最傳統(tǒng)且兼容性最好的方式,利用圖片請求沒有跨域限制的特性。
代碼如下:
// 將屬性對象轉(zhuǎn)換為URL參數(shù)字符串
function formatParams(params) {
return Object.keys(params)
.map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
.join("&");
}
// 使用 Image Beacon
document.getElementById("ImageBeacon").addEventListener("click", () => {
// 構(gòu)建埋點URL和參數(shù)
const saUrl = "https://..."; // 數(shù)據(jù)接收地址
const project = "fosun_test1"; // 您的項目名
const event = "ButtonClick"; // 事件名稱,如 'PageView', 'ButtonClick'
const distinctId = "user_123"; // 用戶ID
const properties = {
// 事件屬性
$url: window.location.href,
button_name: "提交按鈕"
};
const finalUrl = `${saUrl}?project=${project}&event=${event}&distinct_id=${distinctId}&${formatParams(properties)}`;
// 創(chuàng)建Image對象發(fā)送請求
const beacon = new Image(1, 1); // 創(chuàng)建一個1x1像素的圖片
beacon.src = finalUrl; // 設(shè)置src即發(fā)起GET請求
// 可選的錯誤處理
beacon.onerror = function () {
console.error("Sensors beacon request failed.");
};
beacon.onload = function () {
console.log("Sensors beacon request successful.");
};
});
截圖如下:

方法二:使用 Navigator.sendBeacon(現(xiàn)代瀏覽器推薦)
這是 HTML5 專門為日志上報設(shè)計的新 API,非常適合埋點場景。
代碼如下:
// 使用 sendBeacon 發(fā)送數(shù)據(jù)
document.getElementById("sendBeacon").addEventListener("click", () => {
// 構(gòu)建數(shù)據(jù)對象
const data = {
project: "fosun_test1",
event: "ButtonClick",
distinct_id: "user_123",
properties: {
$url: window.location.href,
button_name: "提交按鈕"
}
};
// 注意:sendBeacon 通常以 POST 方式發(fā)送字符串化的JSON
const blob = new Blob([JSON.stringify(data)], { type: "application/x-www-form-urlencoded" });
const success = navigator.sendBeacon("https://...", blob); // 數(shù)據(jù)接收地址
if (success) {
console.log("Beacon enqueued successfully!");
} else {
console.error("Beacon failed to queue.");
}
});
截圖如下:

優(yōu)點:
- 專為日志設(shè)計:即使頁面卸載也會保證發(fā)送。
- 低優(yōu)先級:不會阻塞頁面卸載過程或與關(guān)鍵操作競爭網(wǎng)絡(luò)資源。
方法三:使用 Fetch API with keepalive(不推薦)
Fetch API 提供了 keepalive 選項,用于在頁面卸載后繼續(xù)發(fā)送請求。這在需要確保數(shù)據(jù)上報的場景下非常有用。
// 使用 fetchKeepalive 發(fā)送數(shù)據(jù)
document.getElementById("keepalive").addEventListener("click", () => {
const data = new URLSearchParams();
data.append("project", "your_project_name");
data.append("event", "ButtonClick");
data.append("distinct_id", "user_123");
data.append(
"properties",
JSON.stringify({
$url: window.location.href,
button_name: "提交按鈕"
})
);
fetch("https://...", {
method: "POST",
body: data,
keepalive: true, // 關(guān)鍵參數(shù):確保請求在頁面卸載后仍能繼續(xù)
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
}).catch((error) => {
console.error("Fetch beacon failed:", error);
});
});
方法四:直接使用神策官方 SDK(最推薦)
實際上,您不需要手動實現(xiàn)這些。神策提供了非常完善的官方 SDK,只需簡單初始化即可。
安裝 SDK:
npm install sa-sdk-javascript
初始化并調(diào)用:
<script> // 初始化神策分析 var sensors = window["sensorsDataAnalytic201505"]; sensors.init({ server_url: "https://your-sensors-data-server.com/sa", // 數(shù)據(jù)接收地址 heatmap: { // 可選:點擊圖/觸達(dá)圖配置 clickmap: "default", scroll_notice_map: "default" } }); // 標(biāo)識用戶 sensors.login("user_123"); // 發(fā)送事件 sensors.track("ButtonClick", { button_name: "提交按鈕" }); </script>
這是最推薦的方式,因為官方 SDK 處理了所有的兼容性、批量上報、重試機(jī)制等復(fù)雜問題。
神策請求參數(shù)詳解
無論用哪種方法,最終發(fā)送給神策服務(wù)器的 URL 通常包含以下核心參數(shù):
| 參數(shù) | 含義 | 示例 |
|---|---|---|
project | 項目名稱 | production |
event | 事件名稱 | $pageview (頁面瀏覽) |
distinct_id | 匿名/用戶 ID | 123456 |
properties | 事件屬性 | { "$url": "https://example.com" } |
time | 事件時間戳(可選) | 1631234567890 |
總結(jié)與選擇
| 方法 | 適用場景 | 優(yōu)點 | 缺點 |
|---|---|---|---|
| Image Beacon | 需要極致兼容性(如舊版 IE) | 兼容性最好,無跨域問題 | 無法發(fā)送大量數(shù)據(jù) |
| sendBeacon | 現(xiàn)代瀏覽器,頁面卸載時上報 | 專為日志設(shè)計,不阻塞卸載 | 兼容性稍差(IE 不支持) |
| fetch keepalive | 現(xiàn)代瀏覽器,需要更多控制 | 功能強(qiáng)大,可控制請求細(xì)節(jié) | 兼容性比 sendBeacon 差 |
| 官方 SDK | 所有生產(chǎn)環(huán)境 | 功能完整,穩(wěn)定可靠,省心 | 需要引入 SDK |
最終建議:對于生產(chǎn)環(huán)境,強(qiáng)烈推薦直接使用神策官方 SDK。它封裝了所有最佳實踐,您只需要關(guān)心業(yè)務(wù)邏輯(觸發(fā)什么事件),而不需要關(guān)心網(wǎng)絡(luò)傳輸?shù)膶崿F(xiàn)細(xì)節(jié)。只有在一些非常特殊的場景下,才需要考慮自己實現(xiàn)埋點請求。
常見問題:神策使用 Image Beacon 是怎么獲取用戶數(shù)據(jù)的?
像神策這種發(fā)送一個圖片給后端,他們是怎么通過圖片分析數(shù)據(jù)的?
神策并不是真的去“分析”圖片本身的內(nèi)容(比如圖片里的像素、顏色等),而是巧妙地利用瀏覽器請求圖片的行為來傳遞數(shù)據(jù)。
可以這樣理解:圖片的 URL(地址)不是指向一張真實的圖片,而實際上是一個精心編排的、包含了你所有埋點數(shù)據(jù)的“代碼字符串”。
整個過程就像一個秘密通信協(xié)議:
核心原理:URL 即消息
埋點系統(tǒng)會動態(tài)生成一個 1x1 像素的透明 GIF 圖片的 URL,但這個 URL 的路徑和參數(shù)部分被用來編碼數(shù)據(jù)。
舉個例子: 一個真實的埋點圖片請求 URL 可能長這樣:
https://data-sensors.com/sa.gif?project=my_web&event=pageview&user_id=123&page_url=https%3A%2F%2Fexample.com&button_name=checkout&time=1631234567890
分解這個 URL:
| URL 部分 | 作用 | 說明 |
|---|---|---|
https://data-sensors.com/sa.gif | 接收端點 | 神策服務(wù)器的地址,路徑叫 sa.gif 只是為了偽裝成圖片。 |
?project=my_web | 查詢參數(shù)(數(shù)據(jù)載體) | 從問號 ? 開始的部分才是關(guān)鍵!這些參數(shù)就是埋點數(shù)據(jù)。 |
&event=pageview | 事件名稱 | 告訴服務(wù)器用戶進(jìn)行了“頁面瀏覽”這個行為。 |
&user_id=123 | 用戶標(biāo)識 | 告訴服務(wù)器是哪個用戶做的。 |
&page_url=... | 事件屬性 | 告訴用戶是在哪個頁面做的。 |
&time=... | 時間戳 | 告訴服務(wù)器事件發(fā)生的確切時間。 |
當(dāng)瀏覽器嘗試加載這個“圖片”時,會發(fā)生以下事情:
- 瀏覽器:認(rèn)為這是一個普通的圖片資源,向
https://data-sensors.com/sa.gif發(fā)起一個 HTTP GET 請求。 - 神策服務(wù)器:
- 接收到這個請求,完全忽略請求的是
.gif這個事實。 - 服務(wù)器端的程序(如 Nginx、Node.js、Java 等)會解析 URL 中的查詢參數(shù)(即
?后面的部分)。 - 將這些參數(shù)(
project=my_web,event=pageview…)解析成結(jié)構(gòu)化的 JSON 數(shù)據(jù)。 - 將這些數(shù)據(jù)存入數(shù)據(jù)庫或大數(shù)據(jù)平臺,用于后續(xù)的分析和計算。
- 最后,服務(wù)器返回一個極其微小的 1x1 像素的透明 GIF 圖片作為響應(yīng)內(nèi)容(就是你響應(yīng)頭里
content-type: image/gif對應(yīng)的內(nèi)容)。
- 接收到這個請求,完全忽略請求的是
- 瀏覽器:接收到這個微小的圖片數(shù)據(jù),并渲染它(當(dāng)然,在頁面上你什么都看不到)。
為什么選擇用圖片(Image Beacon)?
這種技術(shù)被稱為 “Image Beacon”(圖片信標(biāo)),它被廣泛采用是因為有諸多優(yōu)點:
| 優(yōu)點 | 解釋 |
|---|---|
| 沒有跨域問題 | 圖片資源不受同源策略的限制,可以從任何域名下加載。這是最大的優(yōu)勢。 |
| 兼容性極好 | 所有瀏覽器,包括非常古老的版本,都支持圖片加載。 |
| 簡單可靠 | 實現(xiàn)起來非常簡單,只需要創(chuàng)建一個 Image 對象并設(shè)置 src 屬性即可。 |
| 不阻塞頁面 | 圖片加載是異步的,不會阻塞頁面的渲染或卸載過程。 |
| 開銷極小 | 請求的圖片只有 1x1 像素,幾乎是所有網(wǎng)絡(luò)請求中數(shù)據(jù)量最小的,對性能影響微乎其微。 |
與現(xiàn)代方法的對比
雖然 Image Beacon 非常經(jīng)典,但現(xiàn)在也有更現(xiàn)代的技術(shù):
| 技術(shù) | 工作原理 | 優(yōu)點 | 缺點 |
|---|---|---|---|
| Image Beacon | 偽裝成圖片的 GET 請求,數(shù)據(jù)在 URL 中 | 兼容性最好,無跨域問題 | URL 長度有限制,不適合傳輸大量數(shù)據(jù) |
| navigator.sendBeacon() | HTML5 新 API,專門用于發(fā)送少量數(shù)據(jù) | 即使頁面關(guān)閉也會保證發(fā)送,不阻塞 | 兼容性稍差(IE 完全不支持) |
| Fetch API | 使用 JavaScript 發(fā)起異步請求 | 功能強(qiáng)大,可控制性強(qiáng) | 可能受跨域策略限制 |
總結(jié)
所以,神策并不是分析圖片,而是掛羊頭賣狗肉:
- 羊頭(請求頭):
Content-Type: image/gif-> 讓瀏覽器以為這是個圖片。 - 狗肉(請求體和目的):
?event=xxx&user_id=xxx-> 在 URL 參數(shù)中攜帶數(shù)據(jù),服務(wù)器解析后存入數(shù)據(jù)庫。
最終,您在海量數(shù)據(jù)中看到的用戶行為分析報表、轉(zhuǎn)化漏斗、留存分析等,全都是基于解析這些 URL 參數(shù)后存入數(shù)據(jù)庫的數(shù)據(jù)計算出來的,與那張微小的透明圖片本身沒有任何關(guān)系。
案例代碼
上面的案例代碼如下:
<!DOCTYPE html>
<html>
<head>
<title>Markdown Renderer</title>
<style>
button {
display: block;
margin: 20px;
font-size: 16px;
}
</style>
</head>
<body>
<div id="result"></div>
<button id="ImageBeacon">ImageBeacon添加埋點</button>
<button id="sendBeacon">Navigator.sendBeacon添加埋點</button>
<button id="keepalive">fetchKeepalive添加埋點</button>
<script>
// 將屬性對象轉(zhuǎn)換為URL參數(shù)字符串
function formatParams(params) {
return Object.keys(params)
.map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
.join("&");
}
// 使用 Image Beacon
document.getElementById("ImageBeacon").addEventListener("click", () => {
// 構(gòu)建埋點URL和參數(shù)
const saUrl = "https://..."; // 數(shù)據(jù)接收地址
const project = "fosun_test1"; // 您的項目名
const event = "ButtonClick"; // 事件名稱,如 'PageView', 'ButtonClick'
const distinctId = "user_123"; // 用戶ID
const properties = {
// 事件屬性
$url: window.location.href,
button_name: "提交按鈕"
};
const finalUrl = `${saUrl}?project=${project}&event=${event}&distinct_id=${distinctId}&${formatParams(properties)}`;
// 創(chuàng)建Image對象發(fā)送請求
const beacon = new Image(1, 1); // 創(chuàng)建一個1x1像素的圖片
beacon.src = finalUrl; // 設(shè)置src即發(fā)起GET請求
// 可選的錯誤處理
beacon.onerror = function () {
console.error("Sensors beacon request failed.");
};
beacon.onload = function () {
console.log("Sensors beacon request successful.");
};
});
// 使用 sendBeacon 發(fā)送數(shù)據(jù)
document.getElementById("sendBeacon").addEventListener("click", () => {
// 構(gòu)建數(shù)據(jù)對象
const data = {
project: "fosun_test1",
event: "ButtonClick",
distinct_id: "user_123",
properties: {
$url: window.location.href,
button_name: "提交按鈕"
}
};
// 注意:sendBeacon 通常以 POST 方式發(fā)送字符串化的JSON
const blob = new Blob([JSON.stringify(data)], { type: "application/x-www-form-urlencoded" });
const success = navigator.sendBeacon("https://...", blob);
if (success) {
console.log("Beacon enqueued successfully!");
} else {
console.error("Beacon failed to queue.");
}
});
// 使用 fetchKeepalive 發(fā)送數(shù)據(jù)
document.getElementById("keepalive").addEventListener("click", () => {
const data = new URLSearchParams();
data.append("project", "your_project_name");
data.append("event", "ButtonClick");
data.append("distinct_id", "user_123");
data.append(
"properties",
JSON.stringify({
$url: window.location.href,
button_name: "提交按鈕"
})
);
fetch("https://...", {
method: "POST", // 也可能是GET,取決于神策服務(wù)器的配置
body: data,
keepalive: true, // 關(guān)鍵參數(shù):確保請求在頁面卸載后仍能繼續(xù)
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
}).catch((error) => {
console.error("Fetch beacon failed:", error);
});
});
</script>
</body>
</html>
總結(jié)
到此這篇關(guān)于前端添加埋點四種方式和原理總結(jié)的文章就介紹到這了,更多相關(guān)前端添加埋點方式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
微信小程序?qū)崿F(xiàn)動態(tài)獲取元素寬高的方法分析
這篇文章主要介紹了微信小程序?qū)崿F(xiàn)動態(tài)獲取元素寬高的方法,結(jié)合實例形式分析了微信小程序動態(tài)獲取、設(shè)置元素寬高的相關(guān)操作技巧與注意事項,需要的朋友可以參考下2018-12-12
微信內(nèi)置瀏覽器私有接口WeixinJSBridge介紹
這篇文章主要介紹了微信內(nèi)置瀏覽器私有接口WeixinJSBridge介紹,本文講解了發(fā)送給好友、分享函數(shù)、隱藏工具欄、隱藏三個點按鈕等功能,需要的朋友可以參考下2015-05-05
利用JS響應(yīng)式修改vue實現(xiàn)頁面的input值
這篇文章主要給大家介紹了關(guān)于如何利用JS響應(yīng)式修改vue實現(xiàn)頁面的input值,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用JS具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09

