主頁 > 企業開發 > 搭建自動化 Web 頁面性能檢測系統 —— 實作篇

搭建自動化 Web 頁面性能檢測系統 —— 實作篇

2023-06-21 08:34:16 企業開發

我們是袋鼠云數堆疊 UED 團隊,致力于打造優秀的一站式資料中臺產品,我們始終保持工匠精神,探索前端道路,為社區積累并傳播經驗價值,,

本文作者:琉易 liuxianyu.cn

前段時間分享了《搭建自動化 Web 頁面性能檢測系統 —— 設計篇》,我們提到了性能檢測的一些名詞和自研性能檢測系統的原因,也簡單介紹了一下系統的設計,在這里我們書接上篇記錄下是如何實作一個性能檢測系統的,

開始前歡迎大家 Star:https://github.com/DTStack/yice-performance

先看下性能檢測系統 —— 易測的實作效果:

file

一、技術選型

服務端框架選擇的是 Nestjs,Web 頁面選擇的是 Vite + React,由于所在團隊當前的研發環境已經全面接入自研的 devops 系統,易測收錄的頁面也是對接 devops 進行檢測的,

1.1、整體架構設計

易測的檢測服務基于 Lighthouse + Puppeteer 實作,下圖是易測的一個整體架構圖:

file

1.2、實作方案

易測的檢測流程是:根據子產品的版本獲取到待檢測的地址、對應的登錄地址、用戶名和密碼,然后通過 Puppeteer 先跳轉到對應的登錄頁面,接著由 Puppeteer 輸入用戶名、密碼、驗證碼,待登錄完成后跳轉至待檢測的頁面,再進行頁面性能檢測,如果登錄后還在登錄頁,表示登錄失敗,則獲取錯誤提示并拋出到日志,為了檢測方便,檢測的均為開發環境且將登錄的驗證碼校驗關閉,

以下是易測的檢測流程圖:

file

二、Lighthouse

易測通過 Node 模塊引入 Lighthouse,不需要登錄的頁面檢測可以直接使用 Lighthouse,基礎用法:

const lighthouse = require('lighthouse');
const runResult = await lighthouse(url, lhOptions, lhConfig);

2.1、options

lhOptions 的主要引數有:

{
  port: PORT, // chrome 運行的埠
  logLevel: 'error',
  output: 'html', // 以 html 檔案的方式輸出報告
  onlyCategories: ['performance'], // 僅采集 performance 資料
  disableStorageReset: true, // 禁止在運行前清除瀏覽器快取和其他存盤 API
}

2.2、config

lhConfig 的主要引數有:

{
  extends: 'lighthouse:default', // 繼承默認配置
  settings: {
    onlyCategories: ['performance'],
    // onlyAudits: ['first-contentful-paint'],
    formFactor: 'desktop',
    throttling: {
      rttMs: 0, // 網路延遲,單位 ms
      throughputKbps: 10 * 1024,
      cpuSlowdownMultiplier: 1,
      requestLatencyMs: 0, // 0 means unset
      downloadThroughputKbps: 0,
      uploadThroughputKbps: 0,
    },
    screenEmulation: {
      mobile: false,
      width: 1440,
      height: 960,
      deviceScaleFactor: 1,
      disabled: false,
    },
    skipAudits: ['uses-http2'], // 跳過的檢查
    emulatedUserAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4695.0 Safari/537.36 Chrome-Lighthouse',
  },
}

settings 屬于 Lighthouse 的運行時配置,主要是用來模擬網路和設備的資訊,以及使用到哪些審查器,如果檢測的頁面有 web 端和 h5 端之分,也是在 settings 進行配置,

檢測結果會有總分、各小項的耗時、瀑布圖、改進建議等,如下:

file

三、Puppeteer

需要登錄后才能訪問的頁面涉及到登錄、點擊等操作,我們需要借助 Puppeteer 來模擬點擊,基礎用法:

const puppeteer = require('puppeteer');

const browser = await puppeteer.launch(puppeteerConfig);
const page = await browser.newPage();

3.1、puppeteerConfig

{
  args: ['--no-sandbox', '--disable-setuid-sandbox', `--remote-debugging-port=${PORT}`],
  headless: true, // 是否使用無頭瀏覽器
  defaultViewport: { width: 1440, height: 960 }, // 指定打開頁面的寬高
  slowMo: 15, // 使 Puppeteer 操作減速,可以觀察到 Puppeteer 的操作
}

headless 為 false 時方便本地除錯,通過調整 slowMo 的大小可以觀察到 Puppeteer 的模擬操作,

四、開始檢測

4.1、主方法

const taskRun = async (task: ITask, successCallback, failCallback, completeCallback) => {
  const { taskId, start, url, loginUrl } = task;
  try {
    // 依據是否包含 devops 來判斷是否需要登錄
    const needLogin = url.includes('devops') || loginUrl;
    console.log(
      `\ntaskId: ${taskId}, 本次檢測${needLogin ? '' : '不'}需要登錄,檢測地址:`,
      url
    );

    // 需要登錄與否會決定使用哪個方法
    const runResult = needLogin ? await withLogin(task) : await withOutLogin(task);

    // 保存檢測結果的報告檔案,便于預覽
    const urlStr = url.replace(/http(s?):\/\//g, '').replace(/\/|#/g, '');
    const fileName = `${moment().format('YYYY-MM-DD')}-${taskId}-${urlStr}`;
    const filePath = `./static/${fileName}.html`;
    const reportPath = `/report/${fileName}.html`;
    fs.writeFileSync(filePath, runResult?.report);

    // 整理性能資料
    const audits = runResult?.lhr?.audits || {};
    const auditRefs =
      runResult?.lhr?.categories?.performance?.auditRefs?.filter((item) => item.weight) || [];
    const { score = 0 } = runResult?.lhr?.categories?.performance || {};

    const performance = [];
    for (const auditRef of auditRefs) {
      const { weight, acronym } = auditRef;
      const { score, numericValue } = audits[auditRef.id] || {};
      if (numericValue =https://www.cnblogs.com/dtux/archive/2023/06/20/== undefined) {
        throw new Error(
          `檢測結果出現問題,沒有單項檢測時長,${JSON.stringify(audits[auditRef.id])}`
        );
      }
      performance.push({
        weight,
        name: acronym,
        score: Math.floor(score * 100),
        duration: Math.round(numericValue * 100) / 100,
      });
    }
    const duration = Number((new Date().getTime() - start).toFixed(2));

    // 匯總檢測結果
    const result = {
      score: Math.floor(score * 100),
      duration,
      reportPath,
      performance,
    };

    // 拋出結果
    await successCallback(taskId, result);

    console.log(`taskId: ${taskId}, 本次檢測耗時:${duration}ms`);
    return result;
  } catch (error) {
    // 錯誤處理
    const failReason = error.toString().substring(0, 10240);
    const duration = Number((new Date().getTime() - start).toFixed(2));
    await failCallback(task, failReason, duration);
    console.error(`taskId: ${taskId}, taskRun error`, `taskRun error, ${failReason}`);
    throw error;
  } finally {
    completeCallback();
  }
};

4.2、不需要登錄

const withOutLogin = async (runInfo: ITask) => {
  const { taskId, url } = runInfo;
  let chrome, runResult;
  try {
    console.log(`taskId: ${taskId}, 開始檢測`);

    // 通過 API 控制 Node 端的 chrome 打開標簽頁,借助 Lighthouse 檢測頁面
    chrome = await chromeLauncher.launch(chromeLauncherOptions);
    runResult = await lighthouse(url, getLhOptions(chrome.port), lhConfig);
    
    console.log(`taskId: ${taskId}, 檢測完成,開始整理資料`);
  } catch (error) {
    console.error(`taskId: ${taskId}, 檢測失敗`, `檢測失敗,${error?.toString()}`);
    throw error;
  } finally {
    await chrome.kill();
  }

  return runResult;
};

4.3、需要登錄

const withLogin = async (runInfo: ITask) => {
  const { taskId, url } = runInfo;
  
  // 創建 puppeteer 無頭瀏覽器
  const browser = await puppeteer.launch(getPuppeteerConfig(PORT));
  const page = await browser.newPage();

  let runResult;
  try {
    // 登錄
    await toLogin(page, runInfo);
    // 選擇租戶
    await changeTenant(page, taskId);

    console.log(`taskId: ${taskId}, 準備作業完成,開始檢測`);

    // 開始檢測
    runResult = await lighthouse(url, getLhOptions(PORT), lhConfig);
    
    console.log(`taskId: ${taskId}, 檢測完成,開始整理資料`);
  } catch (error) {
    console.error(`taskId: ${taskId}, 檢測出錯`, `${error?.toString()}`);
    throw error;
  } finally {
    // 檢測結束關閉標簽頁、無頭瀏覽器
    await page.close();
    await browser.close();
  }

  return runResult;
};

4.4、模擬登錄

所在團隊的子產品均需要登錄后才能訪問,且每次檢測打開的都是類似無痕瀏覽器的標簽頁,不存在登錄資訊的快取,所以每次檢測這些頁面前需要完成登錄操作:

const toLogin = async (page, runInfo: ITask) => {
  const { taskId, loginUrl, username, password } = runInfo;
  try {
    await page.goto(loginUrl);
    // 等待指定的選擇器匹配元素出現在頁面中
    await page.waitForSelector('#username', { visible: true });

    // 用戶名、密碼、驗證碼
    const usernameInput = await page.$('#username');
    await usernameInput.type(username);
    const passwordInput = await page.$('#password');
    await passwordInput.type(password);
    const codeInput = await page.$('.c-login__container__form__code__input');
    await codeInput.type('bz4x');

    // 登錄按鈕
    await page.click('.c-login__container__form__btn');
    // await page.waitForNavigation();
    await sleep(Number(process.env.RESPONSE_SLEEP || 0) * 2);

    const currentUrl = await page.url();
    // 依據是否包含 login 來判斷是否需要登錄,若跳轉之后仍在登錄頁,說明登錄出錯
    if (currentUrl.includes('login')) {
      throw new Error(`taskId: ${taskId}, 登錄失敗,仍在登錄頁面`);
    } else {
      console.log(`taskId: ${taskId}, 登錄成功`);
    }
  } catch (error) {
    console.error(`taskId: ${taskId}, 登錄出錯`, error?.toString());
    throw error;
  }
};

4.5、得分落庫

等待所有的檢測步驟都完成后,在 successCallback 方法中處理檢測資料,此時可根據不同的性能指標計算得出最終得分和小項得分,統一落庫,

五、自動檢測

除了可以在頁面手動觸發檢測,易測主要使用的是自動檢測,自動檢測的目的是方便統計所有子產品的性能趨勢,便于分析各版本間的性能變化,以及子產品間的性能優劣,最終得出優化方向,

5.1、任務主動調度

易測驗運行階段,由于使用的是開發環境進行檢測,所以將自動檢測時間設定為作業時間的間隙,減少影響檢測結果的干擾因素,后續正式部署后,也將調低檢測的頻率,

file

自動檢測可以主動進行任務的調度,也可以手動觸發任務,借助 @nestjs/schedule 實作定時任務:

import { Cron } from '@nestjs/schedule';

export class TaskRunService {
  // 每分鐘執行一次 https://docs.nestjs.com/techniques/task-scheduling#declarative-cron-jobs
  @Cron('0 * * * * *')
  async handleCron() {
    // 檢測版本的 cron 符合當前時間運行的則創建任務
    process.env.NODE_ENV === 'production' && this.checkCronForCurrentDate();
  }
}

5.2、失敗告警

檢測失敗會有釘釘通知,點擊可快速跳轉至易測內查看具體原因,

file

file

5.3、性能趨勢圖

由下方的趨勢圖簡單分析后,可以得出子產品版本間的性能變化,

file

六、對接內部系統

6.1、對接 Jenkins

所在團隊的子產品在版本間做了一些腳手架的封裝升級,對接 Jenkins 就可以采集到各個版本間構建時長和構建后的檔案大小等資訊的變化,有助于性能相關資料的匯總、腳手架的分析改進,
在 Jenkins 的構建回呼里,處理后可以拿到構建時長和構建后的檔案大小等資訊,由 Jenkins 呼叫易測提供的介面,按分支處理好版本后將資料落庫,在易測中展示出來,

七、結尾

如果你也準備搭建一個自己團隊的檢測系統,可以參考下易測的設計思路,希望這兩篇文章對你的作業有所助力,
完成上述作業后,接下來需要考慮的有易測功能的權限控制、資料分析、如何根據業務場景進行檢測等方面,畢竟 Lighthouse 檢測的一般是單個頁面,而業務場景一般是作業流程的編排即流程的整體操作,

最后,歡迎大家不吝 Star:https://github.com/DTStack/yice-performance


最后

歡迎關注【袋鼠云數堆疊UED團隊】~
袋鼠云數堆疊UED團隊持續為廣大開發者分享技術成果,相繼參與開源了歡迎star

  • 大資料分布式任務調度系統——Taier
  • 輕量級的 Web IDE UI 框架——Molecule
  • 針對大資料領域的 SQL Parser 專案——dt-sql-parser
  • 袋鼠云數堆疊前端團隊代碼評審工程實踐檔案——code-review-practices
  • 一個速度更快、配置更靈活、使用更簡單的模塊打包器——ko

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/555711.html

標籤:其他

上一篇:StencilJs學習之事件

下一篇:返回列表

標籤雲
其他(161408) Python(38243) JavaScript(25511) Java(18250) C(15238) 區塊鏈(8271) C#(7972) AI(7469) 爪哇(7425) MySQL(7259) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5875) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4606) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2436) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1984) HtmlCss(1970) 功能(1967) Web開發(1951) C++(1942) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1881) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 搭建自動化 Web 頁面性能檢測系統 —— 實作篇

    >我們是[袋鼠云數堆疊 UED 團隊](http://ued.dtstack.cn/),致力于打造優秀的一站式資料中臺產品。我們始終保持工匠精神,探索前端道路,為社區積累并傳播經驗價值。。 >本文作者:琉易 [liuxianyu.cn](https://link.juejin.cn/?target=h ......

    uj5u.com 2023-06-21 08:34:16 more
  • StencilJs學習之事件

    其實并沒有所謂的 stencil Event,相反 stencil 鼓勵使用 `DOM event`。然而,Stencil 提供了一個 API 來指定組件可以觸發的事件,以及組件監聽的事件。 這是通過 Event()和 Listen()裝飾器實作的。 ## Event 裝飾器 組件可以使用事件發射器 ......

    uj5u.com 2023-06-21 08:34:06 more
  • CSS3有哪些新特性

    CSS3引入了很多新特性,比如: 1. 選擇器:CSS3引入了新的選擇器,如偽類選擇器、偽元素選擇器等,使得選擇元素更加靈活和精確。 2. 邊框圓角:CSS3允許通過 border-radius 屬性為元素的邊框添加圓角,創建圓形、橢圓形或具有不同角度的矩形邊框。 3. 盒陰影:使用 box-sha ......

    uj5u.com 2023-06-21 08:34:02 more
  • js如何操作video標簽

    一.簡介 在做web ui自動化時,遇到操作視頻的時候有時比較讓人頭疼,定位時會發現只有一個<video>標簽,用selenium來實作的話比較麻煩,使用js后我們只需定位到video標簽,然后通過js 中處理video的相關屬性和方法就可實作,我們繼續往下看。 二.實體用法 1.獲取視頻的總時長( ......

    uj5u.com 2023-06-21 08:33:49 more
  • StencilJs學習之事件

    其實并沒有所謂的 stencil Event,相反 stencil 鼓勵使用 `DOM event`。然而,Stencil 提供了一個 API 來指定組件可以觸發的事件,以及組件監聽的事件。 這是通過 Event()和 Listen()裝飾器實作的。 ## Event 裝飾器 組件可以使用事件發射器 ......

    uj5u.com 2023-06-21 08:33:44 more
  • 搭建自動化 Web 頁面性能檢測系統 —— 實作篇

    >我們是[袋鼠云數堆疊 UED 團隊](http://ued.dtstack.cn/),致力于打造優秀的一站式資料中臺產品。我們始終保持工匠精神,探索前端道路,為社區積累并傳播經驗價值。。 >本文作者:琉易 [liuxianyu.cn](https://link.juejin.cn/?target=h ......

    uj5u.com 2023-06-21 08:33:11 more
  • CSS3有哪些新特性

    CSS3引入了很多新特性,比如: 1. 選擇器:CSS3引入了新的選擇器,如偽類選擇器、偽元素選擇器等,使得選擇元素更加靈活和精確。 2. 邊框圓角:CSS3允許通過 border-radius 屬性為元素的邊框添加圓角,創建圓形、橢圓形或具有不同角度的矩形邊框。 3. 盒陰影:使用 box-sha ......

    uj5u.com 2023-06-21 08:33:00 more
  • ChatGPT的ABAP能力如何?

    ChatGPT是最近的熱門話題,作為語言模型,它擅長處理各種語言相關的問題。顯然,ABAP也是一種語言,ABAP開發者的很大一部分作業就是把自然語言和ABAP語言做互相轉換,這應該也是在ChatGPT的擅長范疇內。那么ChatGPT能做好ABAP開發者的作業嗎?本文記錄了我的一些使用經驗和感想。 1 ......

    uj5u.com 2023-06-21 08:32:35 more
  • 構建新型智能化檔案十防一體化管理平臺系統

    檔案館庫房八防溫濕度空氣質量一體化解決方案 檔案庫房是檔案事業發展的基石,其主要任務是集中保管國家機構及個人等在各種形式下形成的具有一定價值和保存價值的各種載體檔案,主要包括文書檔案、科技檔案、會計檔案、人事檔案、實物檔案等。隨著我國經濟和社會的發展,檔案館建設正逐步加強,但檔案館庫房的環境條件也隨 ......

    uj5u.com 2023-06-21 08:32:32 more
  • 華三交換機配置IRF堆疊

    IRF(Intelligent Resilient Framework,智能彈性架構)是H3C自主研發的軟體虛擬化的技術。它的核心思路是將多太設備通過IRF物理埠連接在一起,進行必要的配置后,虛擬化成一臺“分布式設備”。理解為堆疊有助于我們更快的理解。 ......

    uj5u.com 2023-06-21 08:27:18 more