編寫"谷歌擴充套件"便捷"自測"埋點上報資訊是否正確

lulu_up發表於2021-11-08

image.png

編寫"谷歌擴充套件"便捷"自測"埋點上報資訊是否正確

推薦我之前寫的谷歌擴充套件入門&svelte入門文章:

記一次前端"chrome擴充套件"簡單易懂的實戰分享會(上)
記一次前端"chrome外掛"基礎實戰分享會(建議收藏)(下篇)
聊聊Svelte.js技術它做了什麼以及如何實現的(上)
聊聊Svelte.js技術它做了什麼以及如何實現的(下)

背景

     每次開發完專案的埋點功能後都需要進行埋點自測, 此時我只能通過在控制檯的Network上進行篩選, 由於埋點的請求引數是個"物件型別", 需要將傳參逐一點開並且找到params這個key, 但是params是一個被json序列化的字串, 需要進行JSON.parse(xxxxx.params);, 然後再開啟它裡面的陣列結構因為可能是多個埋點資訊一起上報所以JSON.parse後是個資料, 最後還要將裡面的十個固有引數過濾掉只看我們新增的埋點引數。

     上述過程很有規律所以可以抽象成一個工具查詢的邏輯, 那我們可以把問題拆解成3步:

  1. (展示)有合適的介面方便顯示你想要的請求資料。
  2. (獲取)攔截到你想要的請求。
  3. (處理)將請求的引數按固定規則解析, 剔除不需要檢視的引數與父級。
  4. (配置)可配置哪些請求需要被監測。

     當然不只是埋點這個功能, 只要你有分析api資料的需求都可以做類似的外掛。

最終效果

image.png

一、模擬資料的定義

     埋點上報資料我這裡展示一個大概的資料結構, 大家根據業務自行調節, 假設下面的資料結構就是埋點上報api的上報引數

[
  {
    events: [
      {
        eventName: "事件名: 點選事件",
        params:
          '{"default1":"xxxxx","default2":"xxxxx","default3":"xxxxx","default4":"xxxxx","default5":"xxxxx","default6":"xxxxx","startTime":"xxxxx","endTime":"xxxxxxx", "new1":"nnnnnn1", "new2":"nnnnnn2"}',
        xxxxxxxx: 1636179764881,
        xxxxxxx: 0,
      },
      {
        eventName: "事件名: 取消事件",
        params:
          '{"default1":"xxxxx","default2":"xxxxx","default3":"xxxxx","default4":"xxxxx","default5":"xxxxx","default6":"xxxxx","startTime":"xxxxx","endTime":"xxxxxxx", "new1":"nnnnnn2", "new3":"nnnnnn3"}',
        xxxxxxxx: 1636179764881,
        xxxxxxx: 0,
      },
    ],
    user: {
      userId: 123,
      userName: "lulu",
    },
    header: {
      app_id: 999,
      os_name: "mac",
      os_version: "10_15_7",
      device_model: "Macintosh",
      language: "zh-CN",
    },
  },
];
  1. 傳參本身是個"物件型別"
  2. 第一層主要是"埋點事件", "使用者資訊", "裝置資訊&更多"
  3. "events"是事件陣列
  4. "eventName"事件名稱, "params"裡面是被"JSON序列化"的事件引數
  5. "params"裡有一些我們不用看的預設值, 因為每個埋點都會帶一些像"路徑資訊"&"停留事件"&"使用者操作路徑"等等的預設資訊, 這些資訊不用我們手動加入所以也就不用每次都看他的正確性。
  6. "new1, new2, new3"是我們新加入的引數, 也就是我們這次重點驗證的引數

二、模擬埋點資料的發出

     編寫兩個按鈕負責上報埋點請求, 方便我們後續的驗證, 新建一個html檔案:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <button onclick="send(`https://zhangzhaosong1.com/`)">點選上報1</button>
    <button onclick="send(`https://zhangzhaosong2.com/`)">點選上報2</button>
    <script>
      function send(url) {
        fetch(url, {
          method: "post",
          headers: {
            "Content-Type": "application/json;charset=utf-8;",
          },
          body: JSON.stringify([
            {
              events: [
                {
                  eventName: "事件名: 點選事件",
                  params:
                    '{"default1":"xxxxx","default2":"xxxxx","default3":"xxxxx","default4":"xxxxx","default5":"xxxxx","default6":"xxxxx","startTime":"xxxxx","endTime":"xxxxxxx", "new1":"nnnnnn1", "new2":"nnnnnn2"}',
                  xxxxxxxx: 1636179764881,
                  xxxxxxx: 0,
                },
                {
                  eventName: "事件名: 取消事件",
                  params:
                    '{"default1":"xxxxx","default2":"xxxxx","default3":"xxxxx","default4":"xxxxx","default5":"xxxxx","default6":"xxxxx","startTime":"xxxxx","endTime":"xxxxxxx", "new1":"nnnnnn2", "new3":"nnnnnn3"}',
                  xxxxxxxx: 1636179764881,
                  xxxxxxx: 0,
                },
              ],
              user: {
                userId: 123,
                userName: "lulu",
              },
              header: {
                app_id: 999,
                os_name: "mac",
                os_version: "10_15_7",
                device_model: "Macintosh",
                language: "zh-CN",
              },
            },
          ]),
        }).then(() => {});
      }
    </script>
  </body>
</html>

     上面html裡面主要做的工作是新增兩個"按鈕", 每次點選發出埋點的模擬上報的post請求, 每個按鈕上報的不一樣所以有兩個按鈕。

image.png

三、建立一個谷歌外掛專案 & 定義圖示

     沒看過基礎課的同學一定要先看看基礎文章, 否則沒法轉換思維。

主檔案

manifest.json

{
  "manifest_version": 2,
  "name": "埋:更方便的觀察埋點資料",
  "description": "更方便的觀察埋點資料",
  "version": "0.1",
  "browser_action": {
    "default_icon": "images/logo.png"
  }
}

上述的圖示大家自由發揮哈

引入外掛

image.png

image.png

image.png

image.png

四、定義控制檯tab

     在manifest.json檔案裡面增加

{
  "manifest_version": 2,
  "name": "埋:更方便的觀察埋點資料",
  "description": "更方便的觀察埋點資料",
  "version": "0.1",
  "browser_action": {
    "default_icon": "images/logo.png"
  },
  "devtools_page": "devtools/index.html" // 這句是新增的
}

devtools/index.html主要功能只是引入js檔案

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script src="./index.js"></script>
</body>
</html>

devtools/index.js主要功能是建立tab

chrome.devtools.panels.create(
  "埋點驗證tab, 還原埋點上報資訊",
  null,
  "../panel/index.html",
  function () {
    console.log("自定義皮膚建立成功!");
  }
);

panel/index.html裡面才是tab的內容區樣式:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div>建立成功</div>
</body>
</html>

image.png

五、初始化svelte專案

     tab裡面的內容我們懶得原生操作dom, 使用"react"框架有點重, 所以這次我選擇了"svelte框架", 具體它的好處可以看看我之前寫的文章(文章放在文章頭部了)。

初始專案
npx degit sveltejs/template devpanel

cd ./devpanel

yarn

我們編輯一下 rollup.config.js檔案, 使得打包後的檔案直接放入panel資料夾裡。

  output: {
    sourcemap: false,
    format: "iife",
    name: "app",
    file: production ? "../panel/index.js" : "public/build/bundle.js",
  },

並且將panel裡面的index.html檔案的檔案引用指向我們的index.js檔案, 以及引入樣式 <link rel="stylesheet" href="./bundle.css">

在這裡執行命令yarn build後的效果如下, 請點選重新整理外掛並且"F12"重新開啟控制檯:

image.png

image.png

開發時候在localhost:5000/, 開發完打包就可以和外掛一起上線了。

六、攔截請求

     核心功能就是攔截請求, 讓我們使用onRequestFinishedapi

chrome.devtools.network.onRequestFinished.addListener((res) => {})

     上面的返回值res的資料格式如下圖:
image.png

     關鍵資訊都有, 請求方法與url可以用來比對是否為需要攔截的請求, 而我們剩下的工作就是對"text"的解析了。

     要注意的是, svelte裡面無法讀取到chrome的值, 所以需要用if (chrome) {}包裹起來, 所以在svelte裡面開發時我使用的是mock資料除錯。

七、處理資料

<script>
  const path = "https://zhangzhaosong.com/";
  import getNowTime from "./getNowTime";

  if (chrome) {
    let checkEvent = "";
    let dataList = [];
    const baseKeyArr = [
      "default1",
      "default2",
      "default3",
      "default4",
      "default5",
      "default6",
      "startTime",
      "endTime",
    ];
    chrome.devtools.network.onRequestFinished.addListener((res) => {
      const req = res.request;
      if (req.method === "POST" && req.url === path) {
        const eventsArr = JSON.parse(req.postData.text);
        eventsArr.forEach((item) => {
          if (item.events) {
            item.events.forEach((event) => {
              const params = JSON.parse(event.params);
              const res = {};
              for (let i in params) {
                if (!baseKeyArr.includes(i)) {
                  res[i] = params[i];
                }
              }
              dataList.unshift({
                res,
                time: getNowTime(),
                eventName: event.eventName,
              });
              dataList = dataList;
            });
          }
        });
        console.log("---", dataList);
      }
    });
  }
</script>

<main>
  <div>list</div>
</main>

<style>
</style>

image.png

  1. baseKeyArr這個陣列裡面是一些埋點預設的key, 用來過濾掉我們不關心的值
  2. path是要攔截的請求地址, 當然也可以換成正則之類的
  3. getNowTime獲取當前的時間

八、簡單設計個樣式

     將上面得到的陣列迴圈顯示出來, 形成一個被攔截的埋點事件的引數list:

<main>
  {#each Object.keys(dataList) as item}
    <div>
      <header>
        <span>{dataList[item].time} : </span>
        <span class="title">{dataList[item].eventName}</span>
      </header>
      <ul>
        {#each Object.keys(dataList[item].res) as key}
          <li>
            <span>{key} :</span>
            <span>{dataList[item].res[key]}</span>
          </li>
        {/each}
      </ul>
    </div>
  {/each}
</main>

<style>
  .title {
    background-color: bisque;
  }
</style>

image.png

九、過濾功能與清除功能

     為了好用我們可以新增一個過濾功能與清除功能, 這樣檢視起來更舒服:

image.png

end

     網站快卡炸了, 這次就是這樣, 希望與你一起進步。

相關文章