<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          前端埋點(diǎn)數(shù)據(jù)收集及上報(bào)方案

          共 9789字,需瀏覽 20分鐘

           ·

          2021-09-30 09:57

          什么是埋點(diǎn)

          埋點(diǎn),它的學(xué)名是事件追蹤(Event Tracking),主要是針對(duì)特定用戶行為或業(yè)務(wù)過(guò)程進(jìn)行捕獲、處理和發(fā)送的相關(guān)技術(shù)及實(shí)施過(guò)程。埋點(diǎn)是數(shù)據(jù)領(lǐng)域的一個(gè)專(zhuān)業(yè)術(shù)語(yǔ),也是互聯(lián)網(wǎng)領(lǐng)域的一個(gè)俗稱(chēng)。

          埋點(diǎn)是產(chǎn)品數(shù)據(jù)分析的基礎(chǔ),一般用于推薦系統(tǒng)的反饋、用戶行為的監(jiān)控和分析、新功能或者運(yùn)營(yíng)活動(dòng)效果的統(tǒng)計(jì)分析等。

          埋點(diǎn)包含兩個(gè)重要概念:事件(event),屬性(param)

          • 事件(event):應(yīng)用中發(fā)生了什么,例如用戶操作、系統(tǒng)事件或系統(tǒng)錯(cuò)誤。以你拍一產(chǎn)品為例,包含以下事件:enter_page(進(jìn)入頁(yè)面)、leave_page(離開(kāi)頁(yè)面)。

          • 屬性(param):為了描述用戶群細(xì)分而定義的屬性,例如語(yǔ)言偏好或地理位置。以“進(jìn)入課后練習(xí)”事件為例,它包含如下事件屬性:enter_from(從哪個(gè)頁(yè)面來(lái)),class_id(課程id)等。

          • 屬性值(value):屬性的維度,即行為觸發(fā)時(shí)的具體維度。例如:enter_from:home(主頁(yè))、system(系統(tǒng))等。

          主流方案

          • 無(wú)痕埋點(diǎn)(全埋點(diǎn)),利用瀏覽器或APP自帶的監(jiān)聽(tīng)方式,對(duì)用戶的瀏覽頁(yè)面、點(diǎn)擊等行為進(jìn)行收集,一般用于粗顆粒度的數(shù)據(jù)分析,例如公司的slardar

            • 數(shù)據(jù)噪聲大,不管有用沒(méi)有,數(shù)據(jù)都會(huì)被收集

            • 無(wú)法定制化埋點(diǎn),無(wú)法采集到指定事件和業(yè)務(wù)屬性

            • 可供DA使用的信息較少

            • 接入簡(jiǎn)單,幾乎無(wú)侵入,不需要額外的開(kāi)發(fā)成本

            • 用戶操作行為收集非常完整,幾乎不會(huì)遺漏

            • 優(yōu)點(diǎn):

            • 缺點(diǎn):

          • 代碼埋點(diǎn),前端開(kāi)發(fā)人員在代碼中自定義監(jiān)聽(tīng)和收集

            • 工作量大,而且對(duì)代碼侵入性很大,后期維護(hù)也不是很方便

            • 可以精確埋點(diǎn),具備明確的事件標(biāo)識(shí)

            • 業(yè)務(wù)屬性非常豐富

            • 埋點(diǎn)觸發(fā)方式可以靈活定義

            • DA使用更方便和精確

            • 優(yōu)點(diǎn):

            • 缺點(diǎn):

          • 埋點(diǎn)sdk,sdk向外暴露上報(bào)埋點(diǎn)的接口,監(jiān)聽(tīng)和收集過(guò)程開(kāi)發(fā)人員無(wú)感知。例如公司的tea

            • 暫時(shí)想不到

            • 業(yè)務(wù)開(kāi)發(fā)只需關(guān)注事件標(biāo)識(shí)、業(yè)務(wù)屬性等

            • 兼顧無(wú)痕埋點(diǎn)優(yōu)點(diǎn)和代碼埋點(diǎn)的優(yōu)勢(shì)

            • 優(yōu)點(diǎn):

            • 缺點(diǎn):

          常見(jiàn)埋點(diǎn)屬性

          通常前端是按照頁(yè)面維度統(tǒng)計(jì)埋點(diǎn)的,常見(jiàn)的事件屬性如下:

          屬性描述
          uid用戶id,若用戶未登陸,則返回特定標(biāo)識(shí)id
          url當(dāng)前事件觸發(fā)頁(yè)面的url
          eventTime觸發(fā)埋點(diǎn)的時(shí)間戳
          localTime觸發(fā)埋點(diǎn)時(shí)的用戶本地時(shí)間,使用標(biāo)準(zhǔn)YYYY-MM-DD HH:mm:ss格式表示,方便后期直接使用字符串查詢(xún)
          deviceType當(dāng)前用戶使用的設(shè)備類(lèi)型,比如apple、三星、chrome等
          deviceId當(dāng)前用戶使用的設(shè)備id
          osType當(dāng)前用戶使用的系統(tǒng)類(lèi)型,比如windows、macos、ios、android等
          osVersion當(dāng)前用戶使用的系統(tǒng)版本
          appVersion當(dāng)前應(yīng)用版本
          appId當(dāng)前應(yīng)用id
          extra自定義數(shù)據(jù),一般是序列化的字符串,且數(shù)據(jù)結(jié)構(gòu)應(yīng)保持穩(wěn)定

          常見(jiàn)埋點(diǎn)事件

          事件上報(bào)時(shí)機(jī)描述
          頁(yè)面停留當(dāng)前頁(yè)面切換或者頁(yè)面卸載時(shí)記錄前一頁(yè)瀏覽時(shí)間
          pv進(jìn)入頁(yè)面時(shí)頁(yè)面訪問(wèn)次數(shù),uv只需要根據(jù)deviceId過(guò)濾
          交互事件用戶交互事件觸發(fā)時(shí)比如點(diǎn)擊、長(zhǎng)按等
          邏輯事件符合邏輯條件時(shí)比如登陸、跳轉(zhuǎn)頁(yè)面等

          性能數(shù)據(jù)采集方案

          目前性能指標(biāo)數(shù)據(jù)大部分來(lái)源于 window.performance API。

          Performance.timing

          參數(shù)名描述
          connectEndHTTP(TCP) 返回瀏覽器與服務(wù)器之間的連接建立時(shí)的時(shí)間戳。如果建立的是持久連接,則返回值等同于fetchStart屬性的值。連接建立指的是所有握手和認(rèn)證過(guò)程全部結(jié)束。
          connectStartHTTP(TCP) 域名查詢(xún)結(jié)束的時(shí)間戳。如果使用了持續(xù)連接(persistent connection),或者這個(gè)信息存儲(chǔ)到了緩存或者本地資源上,這個(gè)值將和 fetchStart一致。
          domComplete當(dāng)前文檔解析完成,即Document.readyState 變?yōu)?'complete'且相對(duì)應(yīng)的readystatechange 被觸發(fā)時(shí)的時(shí)間戳
          domContentLoadedEventEnd當(dāng)所有需要立即執(zhí)行的腳本已經(jīng)被執(zhí)行(不論執(zhí)行順序)時(shí)的時(shí)間戳。
          domContentLoadedEventStart當(dāng)解析器發(fā)送DOMContentLoaded 事件,即所有需要被執(zhí)行的腳本已經(jīng)被解析時(shí)的時(shí)間戳。
          domInteractive當(dāng)前網(wǎng)頁(yè)DOM結(jié)構(gòu)結(jié)束解析、開(kāi)始加載內(nèi)嵌資源時(shí)(即Document.readyState屬性變?yōu)椤癷nteractive”、相應(yīng)的readystatechange事件觸發(fā)時(shí))的時(shí)間戳。
          domLoading當(dāng)前網(wǎng)頁(yè)DOM結(jié)構(gòu)開(kāi)始解析時(shí)(即Document.readyState屬性變?yōu)椤發(fā)oading”、相應(yīng)的 readystatechange事件觸發(fā)時(shí))的時(shí)間戳。
          domainLookupEndDNS 域名查詢(xún)完成的時(shí)間。如果使用了本地緩存(即無(wú) DNS 查詢(xún))或持久連接,則與 fetchStart 值相等
          domainLookupStartDNS 域名查詢(xún)開(kāi)始的UNIX時(shí)間戳。如果使用了持續(xù)連接(persistent connection),或者這個(gè)信息存儲(chǔ)到了緩存或者本地資源上,這個(gè)值將和fetchStart一致。
          fetchStart瀏覽器準(zhǔn)備好使用HTTP請(qǐng)求來(lái)獲取(fetch)文檔的時(shí)間戳。這個(gè)時(shí)間點(diǎn)會(huì)在檢查任何應(yīng)用緩存之前。
          loadEventEnd當(dāng)load事件結(jié)束,即加載事件完成時(shí)的時(shí)間戳。如果這個(gè)事件還未被發(fā)送,或者尚未完成,它的值將會(huì)是0.
          loadEventStartload事件被發(fā)送時(shí)的時(shí)間戳。如果這個(gè)事件還未被發(fā)送,它的值將會(huì)是0。
          navigationStart同一個(gè)瀏覽器上一個(gè)頁(yè)面卸載(unload)結(jié)束時(shí)的時(shí)間戳。如果沒(méi)有上一個(gè)頁(yè)面,這個(gè)值會(huì)和fetchStart相同。
          redirectEnd最后一個(gè)HTTP重定向完成時(shí)(也就是說(shuō)是HTTP響應(yīng)的最后一個(gè)比特直接被收到的時(shí)間)的時(shí)間戳。如果沒(méi)有重定向,或者重定向中的一個(gè)不同源,這個(gè)值會(huì)返回0.
          redirectStart第一個(gè)HTTP重定向開(kāi)始時(shí)的時(shí)間戳。如果沒(méi)有重定向,或者重定向中的一個(gè)不同源,這個(gè)值會(huì)返回0。
          requestStart返回瀏覽器向服務(wù)器發(fā)出HTTP請(qǐng)求時(shí)(或開(kāi)始讀取本地緩存時(shí))的時(shí)間戳。
          responseEnd返回瀏覽器從服務(wù)器收到(或從本地緩存讀取,或從本地資源讀?。┳詈笠粋€(gè)字節(jié)時(shí)(如果在此之前HTTP連接已經(jīng)關(guān)閉,則返回關(guān)閉時(shí))的時(shí)間戳。
          responseStart返回瀏覽器從服務(wù)器收到(或從本地緩存讀?。┑谝粋€(gè)字節(jié)時(shí)的時(shí)間戳。如果傳輸層在開(kāi)始請(qǐng)求之后失敗并且連接被重開(kāi),該屬性將會(huì)被數(shù)制成新的請(qǐng)求的相對(duì)應(yīng)的發(fā)起時(shí)間
          secureConnectionStartHTTPS 返回瀏覽器與服務(wù)器開(kāi)始安全鏈接的握手時(shí)的時(shí)間戳。如果當(dāng)前網(wǎng)頁(yè)不要求安全連接,則返回0。
          unloadEventEnd和 unloadEventStart 相對(duì)應(yīng),unload事件處理完成時(shí)的時(shí)間戳。如果沒(méi)有上一個(gè)頁(yè)面,這個(gè)值會(huì)返回0。
          unloadEventStart上一個(gè)頁(yè)面unload事件拋出時(shí)的時(shí)間戳。如果沒(méi)有上一個(gè)頁(yè)面,這個(gè)值會(huì)返回0。

          常見(jiàn)性能指標(biāo)

          指標(biāo)名描述
          FP頁(yè)面首次繪制時(shí)間
          FCP頁(yè)面首次有內(nèi)容繪制的時(shí)間
          FMP頁(yè)面首次有效繪制時(shí)間,F(xiàn)MP >= FCP
          TTI頁(yè)面完全可交互時(shí)間
          FID頁(yè)面加載階段,用戶首次交互操作的延時(shí)時(shí)間
          MPFID頁(yè)面加載階段,用戶交互操作可能遇到的最大延時(shí)時(shí)間
          LOAD頁(yè)面完全加載的時(shí)間(load 事件發(fā)生的時(shí)間)

          FP

          FP (First Paint)指標(biāo)通常會(huì)反映頁(yè)面的白屏?xí)r間,而白屏?xí)r間會(huì)反映當(dāng)前 Web 頁(yè)面的網(wǎng)絡(luò)加載性能情況,當(dāng)加載性能非常良好的情況下,白屏的時(shí)間就會(huì)越短,用戶等待內(nèi)容的時(shí)間就會(huì)越短,流失的概率就會(huì)降低。

          該指標(biāo)可以通過(guò) performance.getEntriesByType('paint') 方法獲取 PerformancePaintTiming API 提供的打點(diǎn)信息,找到 name 為 first-paint 的對(duì)象,描述的即為 FP 的指標(biāo)數(shù)據(jù),如下圖所示:

          FCP

          FCP (First Contentful Paint) 為首次有內(nèi)容渲染的時(shí)間點(diǎn),在性能統(tǒng)計(jì)指標(biāo)中,從用戶開(kāi)始訪問(wèn) Web 頁(yè)面的時(shí)間點(diǎn)到 FCP 的時(shí)間點(diǎn)這段時(shí)間可以被視為無(wú)內(nèi)容時(shí)間,一般 FCP >= FP。

          該指標(biāo)可以通過(guò) performance.getEntriesByType('paint') 方法獲取 PerformancePaintTiming API 提供的打點(diǎn)信息,找到 name 為 first-contentful-paint 的對(duì)象,描述的即為 FCP 的指標(biāo)數(shù)據(jù),如下圖所示:

          FMP

          FMP(First Meaningful Paint),即首次繪制有意義內(nèi)容的時(shí)間,當(dāng)整體頁(yè)面的布局和文字內(nèi)容全部渲染完成后,即可認(rèn)為是完成了首次有意義內(nèi)容的繪制。所以 FMP 衡量了用戶看到網(wǎng)頁(yè)的主要內(nèi)容的時(shí)間,是用戶體驗(yàn)角度的一種重要的衡量指標(biāo)。

          前端業(yè)界現(xiàn)在比較認(rèn)可的一個(gè)計(jì)算 FMP 的方式就是「頁(yè)面在加載和渲染過(guò)程中最大布局變動(dòng)之后的那個(gè)繪制時(shí)間 」??赏ㄟ^(guò) MutationObserver 監(jiān)聽(tīng)每一次頁(yè)面整體的 DOM 變化,觸發(fā) MutationObserver 的回調(diào),在回調(diào)計(jì)算出當(dāng)前 DOM 樹(shù)的變動(dòng)分?jǐn)?shù),分?jǐn)?shù)變化最劇烈的時(shí)刻,即為 FMP 的時(shí)間點(diǎn)。

          TTI

          TTI(Time To Interactive),即從頁(yè)面加載開(kāi)始到頁(yè)面處于完全可交互狀態(tài)所花費(fèi)的時(shí)間。頁(yè)面處于完全可交互狀態(tài)時(shí),滿足以下 3 個(gè)條件:

          1. 頁(yè)面已經(jīng)顯示有用內(nèi)容。

          2. 頁(yè)面上的可見(jiàn)元素關(guān)聯(lián)的事件響應(yīng)函數(shù)已經(jīng)完成注冊(cè)。

          3. 事件響應(yīng)函數(shù)可以在事件發(fā)生后的 50ms 內(nèi)開(kāi)始執(zhí)行。

          資源加載指標(biāo)

          window.performance.getEntriesByType('resource')會(huì)返回當(dāng)前頁(yè)面加載的所有資源(js、css、img...)的各類(lèi)性能指標(biāo),可用于靜態(tài)資源性能數(shù)據(jù)采集。

          主要類(lèi)型有:script、link、img、css、xmlhttprequest、beacon、fetch、other。PerformanceResourceTiming - Web APIs | MDN

          參數(shù)名描述
          connectEnd一個(gè) DOMHighResTimeStamp,表示瀏覽器完成建立與服務(wù)器的連接以檢索資源之后的時(shí)間。
          connectStart一個(gè) DOMHighResTimeStamp,表示瀏覽器開(kāi)始建立與服務(wù)器的連接以檢索資源之前的時(shí)間。
          decodedBodySize一個(gè) number,表示在刪除任何應(yīng)用的內(nèi)容編碼之后,從消息主體的請(qǐng)求(HTTP 或緩存)中接收到的大?。ㄒ园宋蛔止?jié)為單位)。
          domainLookupEnd一個(gè) DOMHighResTimeStamp,表示瀏覽器完成資源的域名查找之后的時(shí)間。
          domainLookupStart一個(gè) DOMHighResTimeStamp,表示在瀏覽器立即開(kāi)始資源的域名查找之前的時(shí)間
          duration返回一個(gè) timestamp,即 responseEnd 和 startTime 屬性的差值。
          encodedBodySize一個(gè) number,表示在刪除任何應(yīng)用的內(nèi)容編碼之前,從有效內(nèi)容主體的請(qǐng)求(HTTP 或緩存)中接收到的大小(以八位字節(jié)為單位)。
          entryType返回 "resource"。
          fetchStart一個(gè) DOMHighResTimeStamp,表示瀏覽器即將開(kāi)始獲取資源之前的時(shí)間。
          initiatorType一個(gè) string,代表啟動(dòng)性能條目的資源的類(lèi)型
          name返回資源 URL。
          nextHopProtocol一個(gè) string,代表用于獲取資源的網(wǎng)絡(luò)協(xié)議,由 ALPN 協(xié)議 ID(RFC7301) 定義。
          redirectEnd一個(gè) DOMHighResTimeStamp,表示收到上一次重定向響應(yīng)的發(fā)送最后一個(gè)字節(jié)時(shí)的時(shí)間。
          redirectStart一個(gè) DOMHighResTimeStamp 代表啟動(dòng)重定向的請(qǐng)求開(kāi)始之前的時(shí)間。
          requestStart一個(gè) DOMHighResTimeStamp,表示瀏覽器開(kāi)始向服務(wù)器請(qǐng)求資源之前的時(shí)間。
          responseEnd一個(gè) DOMHighResTimeStamp,表示在瀏覽器接收到資源的最后一個(gè)字節(jié)之后或在傳輸連接關(guān)閉之前(以先到者為準(zhǔn))的時(shí)間。
          responseStart一個(gè) DOMHighResTimeStamp,表示瀏覽器從服務(wù)器接收到響應(yīng)的第一個(gè)字節(jié)后的時(shí)間。
          secureConnectionStart一個(gè) DOMHighResTimeStamp,表示瀏覽器即將開(kāi)始握手過(guò)程以保護(hù)當(dāng)前連接之前的時(shí)間。
          serverTiming一個(gè) PerformanceServerTiming 數(shù)組,包含服務(wù)器計(jì)時(shí)指標(biāo)的 PerformanceServerTiming 條目。
          startTime返回一個(gè) timestamp,表示資源獲取開(kāi)始的時(shí)間。該值等效于 fetchStart。
          transferSize一個(gè) number 代表所獲取資源的大?。ㄒ园宋蛔止?jié)為單位)。該大小包括響應(yīng)標(biāo)頭字段以及響應(yīng)有效內(nèi)容主體。
          workerStart一個(gè) DOMHighResTimeStamp, 如果服務(wù) Worker 線程已經(jīng)在運(yùn)行,則返回在分派 FetchEvent 之前的時(shí)間戳,如果尚未運(yùn)行,則返回在啟動(dòng) Service Worker 線程之前的時(shí)間戳。如果服務(wù) Worker 未攔截該資源,則該屬性將始終返回 0。

          其他指標(biāo)計(jì)算方式

          指標(biāo)名描述計(jì)算方式
          DNS查詢(xún)DNS 階段耗時(shí)domainLookupEnd - domainLookupStart
          TCP連接TCP 階段耗時(shí)connectEnd - connectStart
          SSL建連SSL 連接時(shí)間connectEnd - secureConnectionStart
          首字節(jié)網(wǎng)絡(luò)請(qǐng)求首字節(jié)響應(yīng)時(shí)間(ttfb)responseStart - requestStart
          內(nèi)容傳輸內(nèi)容傳輸,Response階段耗時(shí)responseEnd - responseStart
          DOM解析Dom解析時(shí)間domInteractive - responseEnd
          資源加載資源加載loadEventStart - domContentLoadedEventEnd
          首字節(jié)首字節(jié)responseStart - fetchStart
          DOM Readydom readydomContentLoadedEventEnd - fetchStart
          redirect時(shí)間重定向時(shí)間redirectEnd - redirectStart
          DOM renderdom渲染耗時(shí)domComplete - domLoading
          load頁(yè)面加載耗時(shí)loadEventEnd - navigationStart
          unload頁(yè)面卸載耗時(shí)unloadEventEnd - unloadEventStart
          請(qǐng)求耗時(shí)請(qǐng)求耗時(shí)responseEnd - requestStart
          白屏?xí)r間白屏?xí)r間domLoading - navigationStart

          錯(cuò)誤數(shù)據(jù)采集方案

          目前所能捕捉的錯(cuò)誤有三種:

          • 資源加載錯(cuò)誤,通過(guò) addEventListener('error', callback, true) 在捕獲階段捕捉資源加載失敗錯(cuò)誤。

          • js 執(zhí)行錯(cuò)誤,通過(guò) window.onerror 捕捉 js 錯(cuò)誤。

            • 跨域的腳本會(huì)給出 "Script Error." 提示,拿不到具體的錯(cuò)誤信息和堆棧信息。此時(shí)需要在script標(biāo)簽增加crossorigin="anonymous"屬性,同時(shí)資源服務(wù)器需要增加CORS相關(guān)配置,比如Access-Control-Allow-Origin: *

          • promise 錯(cuò)誤,通過(guò) addEventListener('unhandledrejection', callback)捕捉 promise 錯(cuò)誤,但是沒(méi)有發(fā)生錯(cuò)誤的行數(shù),列數(shù)等信息,只能手動(dòng)拋出相關(guān)錯(cuò)誤信息。

          // 在捕獲階段,捕獲資源加載失敗錯(cuò)誤
          addEventListener('error', e => {
          const target = e.target
          if (target != window) {
          monitor.errors.push({
          type: target.localName,
          url: target.src || target.href,
          msg: (target.src || target.href) + ' is load error',
          time: Date.now()
          })
          }
          }, true)

          // 監(jiān)聽(tīng) js 錯(cuò)誤
          window.onerror = function(msg, url, row, col, error) {
          monitor.errors.push({
          type: 'javascript',
          row: row,
          col: col,
          msg: error && error.stack? error.stack : msg,
          url: url,
          time: Date.now()
          })
          }

          // 監(jiān)聽(tīng) promise 錯(cuò)誤 缺點(diǎn)是獲取不到行數(shù)數(shù)據(jù)
          addEventListener('unhandledrejection', e => {
          monitor.errors.push({
          type: 'promise',
          msg: (e.reason && e.reason.msg) || e.reason || '',
          time: Date.now()
          })
          })
          復(fù)制代碼

          數(shù)據(jù)上報(bào)方案

          在這個(gè)場(chǎng)景中,需要考慮兩個(gè)問(wèn)題:

          • 如果數(shù)據(jù)上報(bào)接口與業(yè)務(wù)系統(tǒng)使用同一域名,瀏覽器對(duì)請(qǐng)求并發(fā)量有限制,所以存在網(wǎng)絡(luò)資源競(jìng)爭(zhēng)的可能性。

          • 瀏覽器通常在頁(yè)面卸載時(shí)會(huì)忽略異步ajax請(qǐng)求,如果需要必須進(jìn)行數(shù)據(jù)請(qǐng)求,一般在unload或者beforeunload事件中創(chuàng)建同步ajax請(qǐng)求,以此延遲頁(yè)面卸載。從用戶側(cè)角度,就是頁(yè)面跳轉(zhuǎn)變慢。

          Beacon

          可以看到,除開(kāi)ie瀏覽器,目前主流現(xiàn)代瀏覽器對(duì)beacon的支持率非常高。Beacon - MDN文檔

          Beacon 接口用來(lái)調(diào)度向 Web 服務(wù)器發(fā)送的異步非阻塞請(qǐng)求。

          • Beacon 請(qǐng)求使用 HTTP POST方法,并且不需要有響應(yīng)。

          • Beacon 請(qǐng)求能確保在頁(yè)面觸發(fā) unload 之前完成初始化。

          通俗的講就是,Beacon可將數(shù)據(jù)異步發(fā)送至服務(wù)端,且能夠保證在頁(yè)面卸載完成前發(fā)送請(qǐng)求(解決ajax頁(yè)面卸載會(huì)終止請(qǐng)求的問(wèn)題)。使用方法如下:

          navigator.sendBeacon(url, data);
          復(fù)制代碼

          其中 data 參數(shù)是可選的,它的類(lèi)型可以為 ArrayBufferViewBlobDOMString 或者 FormData。如果瀏覽器成功地將 beacon 請(qǐng)求加入到待發(fā)送的隊(duì)列里,這個(gè)方法將會(huì)返回 true ,否則將會(huì)返回 false

          使用Beacon時(shí)需要后臺(tái)需要使用post方法接收參數(shù),考慮到跨域問(wèn)題,后臺(tái)還需要改造接口配置CORS。同時(shí)請(qǐng)求頭必須滿足CORS-safelisted request-header,其中content-type的類(lèi)型必須為application/x-www-form-urlencodedmultipart/form-data, 或者text/plain。

          type ContentType = 'application/x-www-form-urlencoded' | 'multipart/form-data' | 'text/plain';

          const serilizeParams = (params: object) => {
          return window.btoa(JSON.stringify(params))
          }

          function sendBeacon(url: string, params: object) {
          const formData = new FormData()
          formData.append('params', serilizeParams(params))
          navigator.sendBeacon(url, formData)
          }
          復(fù)制代碼

          Image

          sendBeacon的兼容性問(wèn)題是不可避免的,不過(guò)可以充分利用大部分瀏覽器會(huì)在頁(yè)面卸載前完成圖片的加載的特性,通過(guò)在頁(yè)面添加img的方式上報(bào)數(shù)據(jù)。

          function sendImage(url: string, params: object) {
          const img = new Image()

          img.style.display = 'none'

          const removeImage = function() {
          img.parentNode.removeChild(img)
          }

          img.onload = removeImage
          img.onerror = removeImage

          img.src = `${url}?params=${serilizeParams(params)}`

          document.body.appendChild(img)
          }
          復(fù)制代碼

          由于img圖片為get請(qǐng)求方式,不同服務(wù)器針對(duì)uri的長(zhǎng)度有限制,長(zhǎng)度超過(guò)限制時(shí)會(huì)出現(xiàn)HTTP 414錯(cuò)誤,所以還要注意上報(bào)頻率,減少一次性上傳的屬性過(guò)多。

          HTTP 1.1 defines Status Code 414 Request-URI Too Long for the cases where a server-defined limit is reached. You can see further details on RFC 2616. For the case of client-defined limits, there is no sense on the server returning something, because the server won't receive the request at all.

          兼容方案

          優(yōu)先使用sendBeacon的方式,Image方式作為fallback。

          function sendLog(url: string, params: object) {
          if(navigator.sendBeacon) {
          sendBeacon(url, params)
          } else {
          sendImage(url, params)
          }
          }
          復(fù)制代碼

          相關(guān)文檔

          • 深入了解前端監(jiān)控原理

          • 前端埋點(diǎn)數(shù)據(jù)收集及上報(bào)方案

          • 本文作者:隨風(fēng)丶逆風(fēng)

          • 本文鏈接:https://juejin.cn/post/6938075086737899534


          瀏覽 50
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲三级片在线视频 | 日韩无码一级片 | 日韩操比视频 | 日本一级婬片A片AAA毛多多 | 日皮视频色 |