<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)方案實(shí)戰(zhàn)

          共 9691字,需瀏覽 20分鐘

           ·

          2021-10-10 16:14

          點(diǎn)擊上方關(guān)注?前端技術(shù)江湖一起學(xué)習(xí),天天進(jìn)步


          什么是埋點(diǎn)

          埋點(diǎn),它的學(xué)名是事件追蹤(Event Tracking),主要是針對特定用戶行為或業(yè)務(wù)過程進(jìn)行捕獲、處理和發(fā)送的相關(guān)技術(shù)及實(shí)施過程。埋點(diǎn)是數(shù)據(jù)領(lǐng)域的一個(gè)專業(yè)術(shù)語,也是互聯(lián)網(wǎng)領(lǐng)域的一個(gè)俗稱。埋點(diǎn)是產(chǎn)品數(shù)據(jù)分析的基礎(chǔ),一般用于推薦系統(tǒng)的反饋、用戶行為的監(jiān)控和分析、新功能或者運(yùn)營活動(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)入頁面)、leave_page(離開頁面)。

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

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

          主流方案

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

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

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

            • 可供DA使用的信息較少

            • 接入簡單,幾乎無侵入,不需要額外的開發(fā)成本

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

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

            • 缺點(diǎn):

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

            • 工作量大,而且對代碼侵入性很大,后期維護(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)聽和收集過程開發(fā)人員無感知。例如公司的tea

            • 暫時(shí)想不到

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

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

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

            • 缺點(diǎn):

          常見埋點(diǎn)屬性

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

          屬性描述
          uid用戶id,若用戶未登陸,則返回特定標(biāo)識(shí)id
          url當(dāng)前事件觸發(fā)頁面的url
          eventTime觸發(fā)埋點(diǎn)的時(shí)間戳
          localTime觸發(fā)埋點(diǎn)時(shí)的用戶本地時(shí)間,使用標(biāo)準(zhǔn)YYYY-MM-DD HH:mm:ss格式表示,方便后期直接使用字符串查詢
          deviceType當(dāng)前用戶使用的設(shè)備類型,比如apple、三星、chrome等
          deviceId當(dāng)前用戶使用的設(shè)備id
          osType當(dāng)前用戶使用的系統(tǒng)類型,比如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)定

          常見埋點(diǎn)事件

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

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

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

          Performance.timing

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

          常見性能指標(biāo)

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

          FP

          FP (First Paint)指標(biāo)通常會(huì)反映頁面的白屏?xí)r間,而白屏?xí)r間會(huì)反映當(dāng)前 Web 頁面的網(wǎng)絡(luò)加載性能情況,當(dāng)加載性能非常良好的情況下,白屏的時(shí)間就會(huì)越短,用戶等待內(nèi)容的時(shí)間就會(huì)越短,流失的概率就會(huì)降低。該指標(biāo)可以通過?performance.getEntriesByType('paint')?方法獲取?PerformancePaintTiming API?提供的打點(diǎn)信息,找到 name 為 first-paint 的對象,描述的即為 FP 的指標(biāo)數(shù)據(jù),如下圖所示:

          FCP

          FCP (First Contentful Paint) 為首次有內(nèi)容渲染的時(shí)間點(diǎn),在性能統(tǒng)計(jì)指標(biāo)中,從用戶開始訪問 Web 頁面的時(shí)間點(diǎn)到 FCP 的時(shí)間點(diǎn)這段時(shí)間可以被視為無內(nèi)容時(shí)間,一般 FCP >= FP。該指標(biāo)可以通過?performance.getEntriesByType('paint')?方法獲取 PerformancePaintTiming API 提供的打點(diǎn)信息,找到 name 為 first-contentful-paint 的對象,描述的即為 FCP 的指標(biāo)數(shù)據(jù),如下圖所示:

          FMP

          FMP(First Meaningful Paint),即首次繪制有意義內(nèi)容的時(shí)間,當(dāng)整體頁面的布局和文字內(nèi)容全部渲染完成后,即可認(rèn)為是完成了首次有意義內(nèi)容的繪制。所以 FMP 衡量了用戶看到網(wǎng)頁的主要內(nèi)容的時(shí)間,是用戶體驗(yàn)角度的一種重要的衡量指標(biāo)。前端業(yè)界現(xiàn)在比較認(rèn)可的一個(gè)計(jì)算 FMP 的方式就是「頁面在加載和渲染過程中最大布局變動(dòng)之后的那個(gè)繪制時(shí)間?」??赏ㄟ^ MutationObserver 監(jiān)聽每一次頁面整體的 DOM 變化,觸發(fā) MutationObserver 的回調(diào),在回調(diào)計(jì)算出當(dāng)前 DOM 樹的變動(dòng)分?jǐn)?shù),分?jǐn)?shù)變化最劇烈的時(shí)刻,即為 FMP 的時(shí)間點(diǎn)。

          TTI

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

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

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

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

          資源加載指標(biāo)

          window.performance.getEntriesByType('resource')會(huì)返回當(dāng)前頁面加載的所有資源(js、css、img...)的各類性能指標(biāo),可用于靜態(tài)資源性能數(shù)據(jù)采集。主要類型有:script、link、img、css、xmlhttprequest、beacon、fetch、other。PerformanceResourceTiming - Web APIs | MDN

          參數(shù)名描述
          connectEnd一個(gè) DOMHighResTimeStamp,表示瀏覽器完成建立與服務(wù)器的連接以檢索資源之后的時(shí)間。
          connectStart一個(gè) DOMHighResTimeStamp,表示瀏覽器開始建立與服務(wù)器的連接以檢索資源之前的時(shí)間。
          decodedBodySize一個(gè) number,表示在刪除任何應(yīng)用的內(nèi)容編碼之后,從消息主體的請求(HTTP 或緩存)中接收到的大?。ㄒ园宋蛔止?jié)為單位)。
          domainLookupEnd一個(gè) DOMHighResTimeStamp,表示瀏覽器完成資源的域名查找之后的時(shí)間。
          domainLookupStart一個(gè) DOMHighResTimeStamp,表示在瀏覽器立即開始資源的域名查找之前的時(shí)間
          duration返回一個(gè) timestamp,即 responseEnd 和 startTime 屬性的差值。
          encodedBodySize一個(gè) number,表示在刪除任何應(yīng)用的內(nèi)容編碼之前,從有效內(nèi)容主體的請求(HTTP 或緩存)中接收到的大?。ㄒ园宋蛔止?jié)為單位)。
          entryType返回 "resource"。
          fetchStart一個(gè) DOMHighResTimeStamp,表示瀏覽器即將開始獲取資源之前的時(shí)間。
          initiatorType一個(gè) string,代表啟動(dòng)性能條目的資源的類型
          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)重定向的請求開始之前的時(shí)間。
          requestStart一個(gè) DOMHighResTimeStamp,表示瀏覽器開始向服務(wù)器請求資源之前的時(shí)間。
          responseEnd一個(gè) DOMHighResTimeStamp,表示在瀏覽器接收到資源的最后一個(gè)字節(jié)之后或在傳輸連接關(guān)閉之前(以先到者為準(zhǔn))的時(shí)間。
          responseStart一個(gè) DOMHighResTimeStamp,表示瀏覽器從服務(wù)器接收到響應(yīng)的第一個(gè)字節(jié)后的時(shí)間。
          secureConnectionStart一個(gè) DOMHighResTimeStamp,表示瀏覽器即將開始握手過程以保護(hù)當(dāng)前連接之前的時(shí)間。
          serverTiming一個(gè) PerformanceServerTiming 數(shù)組,包含服務(wù)器計(jì)時(shí)指標(biāo)的 PerformanceServerTiming 條目。
          startTime返回一個(gè) timestamp,表示資源獲取開始的時(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查詢DNS 階段耗時(shí)domainLookupEnd - domainLookupStart
          TCP連接TCP 階段耗時(shí)connectEnd - connectStart
          SSL建連SSL 連接時(shí)間connectEnd - secureConnectionStart
          首字節(jié)網(wǎng)絡(luò)請求首字節(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頁面加載耗時(shí)loadEventEnd - navigationStart
          unload頁面卸載耗時(shí)unloadEventEnd - unloadEventStart
          請求耗時(shí)請求耗時(shí)responseEnd - requestStart
          白屏?xí)r間白屏?xí)r間domLoading - navigationStart

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

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

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

          • js 執(zhí)行錯(cuò)誤,通過?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ò)誤,通過?addEventListener('unhandledrejection', callback)捕捉 promise 錯(cuò)誤,但是沒有發(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)聽?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)聽?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()
          ????})
          })

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

          在這個(gè)場景中,需要考慮兩個(gè)問題:

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

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

          Beacon

          可以看到,除開ie瀏覽器,目前主流現(xiàn)代瀏覽器對beacon的支持率非常高。Beacon - MDN文檔Beacon 接口用來調(diào)度向 Web 服務(wù)器發(fā)送的異步非阻塞請求。

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

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

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

          navigator.sendBeacon(url,?data);

          其中 data 參數(shù)是可選的,它的類型可以為?ArrayBufferView,?Blob,?DOMString?或者?FormData。如果瀏覽器成功地將 beacon 請求加入到待發(fā)送的隊(duì)列里,這個(gè)方法將會(huì)返回 true ,否則將會(huì)返回 false使用Beacon時(shí)需要后臺(tái)需要使用post方法接收參數(shù),考慮到跨域問題,后臺(tái)還需要改造接口配置CORS。同時(shí)請求頭必須滿足CORS-safelisted request-header,其中content-type的類型必須為application/x-www-form-urlencoded,?multipart/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)
          }

          Image

          sendBeacon的兼容性問題是不可避免的,不過可以充分利用大部分瀏覽器會(huì)在頁面卸載前完成圖片的加載的特性,通過在頁面添加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)
          }

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

          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ēng)丶逆風(fēng)

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


          The End

          歡迎自薦投稿到《前端技術(shù)江湖》,如果你覺得這篇內(nèi)容對你挺有啟發(fā),記得點(diǎn)個(gè)?「在看」

          點(diǎn)個(gè)『在看』支持下?

          瀏覽 44
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(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>
                  aaaaaa大片 | 在线观看免费视频一区 | 下面喷水视频 | 高清无码视频网站 | 日韩av手机在线 日韩va在线观看 |