Community研究與資料分析github.com

alii13/overfetch: 請求審計工具

審計前端應用程式與後端通訊的方式,產出一個有證據支持的排名報告,指出請求放大問題並提供具體修復方案,包括逐行 N+1 查詢、重複請求、堆疊輪詢計時器、零新鮮度、全面失效、序列瀑布流、全抓分頁、過度擷取和重試浪費。當有人問為何應用程式發出太多請求、需要進行網路/請求/資料擷取/API 呼叫審計、提及 N+1、瀑布流、輪詢、重新擷取風暴、速率限制時,使用此工具。

overfetch: 請求審計工具 是什麼?

`overfetch` 是一個專門針對前端應用程式與其後端通訊進行審計的技能。它不僅僅是一個靜態分析工具,還會結合動態捕獲(如 HAR 檔案)來產生一份基於實際證據的排名報告,詳細列出應用程式中比螢幕實際需求發出更多請求的各種情況。此技能專注於找出請求放大問題,包括經典的 N+1 查詢、重複擷取、序列瀑布流、不正確的輪詢設定、無效的過期策略等。它支援多種主流資料擷取庫(如 TanStack Query、SWR、Apollo、RTK Query)和前端框架(如 Next.js、Remix、SvelteKit),並提供一個嚴格的工作流程,包含範圍界定、覆蓋圖繪製、靜態掃描、候選項目驗證、跨域檢查和即時捕獲。其輸出是一份結構清晰的 Markdown 報告,包含發現、非發現、待決的產品決策和審計限制,非常適合開發者或 AI 代理用來診斷和解決網路請求效率問題。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/alii13/overfetch/tree/HEAD

Installed? Explore more 研究與資料分析 skills: affaan-m/uspto-database, affaan-m/scholar-evaluation, affaan-m/literature-review · View all 6 →

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

overfetch:請求審計

您正在製作一份可供他人執行的報告:一份排名清單,列出此應用程式比其畫面所需發出更多請求的方式,每項都附有證據、修復方案以及應減少的數量。此報告只有在每項發現都能經得起懷疑讀者的考驗時才有用,因此下述方法花費大部分精力在驗證以及明確說明已檢查和未檢查的項目。

您交付的內容

一份 Markdown 報告(範本在 references/report-template.md),包含:

  1. 範圍和證據:什麼專案樹、哪個提交、哪些捕獲。
  2. 覆蓋範圍:每個路由、每個懶載入區塊和每個條件資料站點,以及哪些僅在程式碼中被讀取,哪些在捕獲中被執行。
  3. 發現:按請求數量的增長方式排名,每個發現都附有 file:line 或捕獲證據、根本原因、修復模式、預期差異、工作量。
  4. 非發現:您檢查過但排除的模式,附有原因。這能阻止下一個人重新調查。
  5. 待決的產品決策和後端需求:需要人類決定或 API 變更,而非客戶端修補程式的項目。
  6. 限制:審計無法衡量的內容。

事後提供實施修復,每個發現一個 PR,按嚴重性從高到低。請勿在審計期間開始修復。

原則

正則表達式命中是候選,不是發現。 scripts/static_scan.py 讀取文字。它無法區分 3 行標籤列和 3,000 行表格,或是在大量匯入後故意的根失效和懶惰的失效。針對您打算報告的每個候選項目的背後程式碼進行閱讀。說明您讀取了什麼。

測量過的事實勝過宣稱的事實。 執行中應用程式的捕獲是關於請求數量的真相;程式碼是關於為何的真相。註解、文件和舊的審計記錄是宣稱。當文件說「60 秒內新鮮」而程式碼說 staleTime: Infinity 時,報告程式碼,註明矛盾,並記錄您讀取的提交雜湊值。

在指責庫之前,先了解其實際語義。 代價最高的錯誤是自信但錯誤的宣稱:「快取會去重」但金鑰不同、「輪詢在空閒時暫停」但僅在隱藏時暫停、「三個呼叫者,每分鐘三次擷取」但庫會重新同步相同金鑰的計時器並共用擷取。references/library-facts.md 包含了 TanStack Query、SWR、Apollo 和 RTK Query 的事實,並附有每個檢查來源的路徑。在撰寫有關快取或輪詢的句子之前,請閱讀所用庫的章節;並且當某個宣稱決定了某項發現時,請打開已安裝庫的原始碼並確認它。

按增長排名,而不是按數量。 一個隨行數、隨掛載的元件數量或隨時間增長而增長的讀取,比固定的重複更糟糕。下面的嚴重性評分標準是關於增長類別。

覆蓋率有一個分母。 捕獲僅能看到在其執行期間載入的程式碼:有人訪問過的路由、有人打開過的對話框和分頁、已開啟的標誌以及後端恰好回傳的狀態。懶載入區塊、條件螢幕和錯誤路徑正是請求錯誤隱藏的地方,因為在開發期間沒有人會去看它們。因此,每次審計都從完整的表面開始(coverage_map.py),每個「沒有問題」都限定在已覆蓋的範圍內,並且報告會說明哪些部分是被實際執行過,哪些僅是被讀取過。

說明哪些是沒問題的。 一個每行去重一次的懸停預取是沒問題的。把它寫下來作為一個。只列出問題的報告會讓讀者懷疑還漏了什麼。

數字皆有出處。 報告中的每個數字都可追溯到一個捕獲檔案或程式碼路徑。不要憑直覺發明「6 次以上」或「大約 100 次」;如果您無法測量,請說「未測量」並給出公式(行數 × 每行讀取次數)。

工作流程

事先告訴使用者這需要多長時間。一個中等規模應用程式的純靜態審計需要 15 到 30 分鐘的閱讀。增加即時捕獲則需要額外 15 到 45 分鐘,取決於需要檢查多少個流程。

1. 範圍界定

  • 從 package.json(掃描工具會印出兩者)找到應用程式的根目錄和資料庫。若是 Monorepo:分別掃描每個應用程式。
  • 找到資料層:查詢鍵工廠、傳輸/服務模組、QueryClient 的建構(或 SWR 設定、Apollo 客戶端、RTK createApi)。先讀取預設值;它們設定了每個發現都將與之比較的基準線。
  • 列出重要的畫面:通常是登入後的首頁、最繁忙的清單,以及任何保持打開數小時的畫面(一個殼層、一個監控畫面)。如果不確定,請詢問使用者;否則選擇這三個並說明理由。
  • 記錄提交:git rev-parse HEAD。報告中的每一行都參照此修訂版本。
  • 決定是否可以進行即時捕獲:一個正在執行的開發伺服器加上一個您可以驅動的瀏覽器,或者使用者已有的 HAR 檔案。如果都沒有,則審計僅為靜態捕獲,並且報告必須在其第一段中說明。

2. 覆蓋範圍圖

python3 <skill-dir>/scripts/coverage_map.py <app-root> --format md --out coverage.md

這是分母。它列出每個路由(針對 TanStack Router、Next.js、Remix、SvelteKit 和 SolidStart 的基於檔案的路由器;透過其路徑字面量定義的程式碼路由器;否則為入口檔案)、每個動態 import() 邊界及其背後的讀取、每個由標誌、平台、權限或環境檢查條件化的資料模組、原始碼中的每個端點路徑字面量,以及沒有路由到達的資料模組。它在一個 2,000 個檔案的應用程式上只需幾秒鐘即可執行完畢。

以三種方式使用它:

  • 用於規劃。 底部的捕獲計畫命名了具有最多讀取站點的路由、要觸發的懶載入區塊以及要切換的條件。使用它來選擇步驟 6 中的流程,而不是猜測。
  • 用於限定掃描範圍。 在沒有路由到達的模組中的發現是死程式碼,或者是由地圖無法解析的某些方式到達的。在將其稱為活躍程式碼之前先檢查一下。
  • 用於閉環。 捕獲完成後,使用捕獲重新執行它;它會標記哪些路由被訪問過,哪些模組和懶載入區塊被載入(對於開發伺服器捕獲是精確的),哪些條件化模組被執行,以及哪些端點路徑出現過:
python3 <skill-dir>/scripts/coverage_map.py <app-root> --har home.har --har library.har --visited home.har.visited.txt --format md

重複進行捕獲,直到具有最多讀取站點的路由和懶載入區塊都被覆蓋,或者記錄下為什麼沒有(沒有測試資料、需要您沒有的角色、無法執行的平台)。

3. 靜態掃描

python3 <skill-dir>/scripts/static_scan.py <app-root> --format md --out scan.md
python3 <skill-dir>/scripts/static_scan.py <app-root> --format json --out scan.json

掃描速度很快(對於 2,000 個檔案大約需要十秒),並且只需要 Python 3.9+。它會輸出帶有嚴重性、信心度、觸發的檢測器、file:line、為何重要的原因、修復模式以及「先驗證」指令的候選項目。完整閱讀 scan.md;JSON 用於腳本化和評估工具。

為預設遺漏的生成目錄添加 --exclude,當清單很長並且您希望第一次掃描更精確時,添加 --min-confidence medium。

4. 驗證候選項目

按此順序處理候選項目:先 P0 按信心度,然後 P1,然後其餘的。對於您保留的每個項目,您必須已開啟該檔案並能夠回答:

  • 每行或每個觀察者的乘數是多少,以及它的邊界是什麼?(對固定列舉進行 .map 不是 N+1。來自分頁清單的行數是。)
  • 快取是否已經吸收了它?(相同的金鑰、暖快取條目、enabled: false 的讀取、已擷取該物件的父元件。)
  • 是否存在客戶端可以使用的批次或投影端點?閱讀 API 用戶端或 OpenAPI 規範。如果沒有,則修復方案是後端需求,並且該發現會保留「後端阻擋」的標記。
  • 根據 references/catalog.md,按名稱修復的模式是什麼?

丟棄未能通過這些檢查的候選項目,並保留那些讀者可能會合理提出的您已丟棄的項目:它們會進入非發現表格,並附上一行原因。

每個檢測器的目錄條目都列出了特定的非發現條件。針對掃描中出現的每個檢測器 ID 閱讀它;它按相同的 ID 組織。

5. 掃描器無法進行的跨域檢查

這些需要閱讀,而不是 grep。全部執行;大多數審計至少會發現一個。

  • 金鑰規範性。 選擇五個最常被讀取的端點,並找出讀取每個端點的所有查詢鍵。一個讀取有兩個金鑰意味著兩個快取條目和兩次擷取。特別要關注在不同投影(完整 vs 僅名稱)下的清單讀取,以及範圍差異(組織 vs 工作區),這些並非真正的不同資料。
  • 共用的進行中讀取。 在同一 frame 中掛載且具有相同金鑰的兩個元件,只有在該時刻金鑰完全相同時,才會共用一個請求。由稍後才穩定下來的狀態(從另一個查詢到達的 ID)組建的金鑰會產生兩次擷取:一次帶有 undefined,一次是真實的。檢查依賴金鑰上的 enabled 條件。
  • 每個表面的新鮮度。 製作一個按資料類型(識別、清單、詳細資訊、即時狀態)分類的 staleTime 表格,並將其與每個資料實際變化的速度進行比較。常見的錯誤是使用一個對任何情況都不合適的全局值。
  • 輪詢所有權。 對於共用鉤子或選項工廠中的每個輪詢選項,列出可以同時掛載的元件以及每個元件使用的金鑰。在 SWR 和 Apollo 中,每個實例執行自己的計時器,並且除非它們落在去重視窗內,否則擷取會倍增。在 TanStack Query 中,計時器會在每次查詢更新時重新啟動,並共用一次擷取,因此相同金鑰的觀察者成本為每個最短間隔一次擷取;堆疊出現在跨金鑰或客戶端時,發現是節奏所有權。在 RTK Query 中,每個快取條目一個計時器以最短間隔執行。
  • 焦點和可見性。 在此平台上,什麼會觸發焦點重新擷取?桌面殼層(Tauri、Electron)通常會連接 OS 視窗焦點,其觸發頻率遠高於分頁可見性。哪些輪詢在隱藏時暫停,哪些在使用者在可見螢幕上空閒時繼續執行?
  • 並行上限。 對於分散式讀取是否有限制器,它是什麼?請注意,6 個並行限制器不是每秒 6 個請求的限制;不要將一個寫成另一個。
  • 分頁契約。 對於未知總數的集合,用戶端是在頁面回傳內容不足時停止,還是繼續請求直到空頁面?檢查頁面大小與畫面可以顯示的內容。
  • 重試。 用戶端在 403/404/422 時做什麼?庫預設重試三次;一個帶有禁止區塊的 100 行 N+1 會變成 400 個請求。
  • 持久化。 如果快取被持久化(IndexedDB、localStorage、原生儲存),什麼是 maxAge,什麼會在部署時清除它,並且儲存是針對每個平台的嗎?持久化快取會改變捕獲中「冷載入」的含義;說明您測量的是哪一種。
  • 突變。 對於最常見的五種寫入操作,哪些會被失效?在小寫入操作之後的根失效是常見的發現。

6. 即時捕獲

如果您可以執行應用程式或者使用者提供了捕獲檔案,則獲取數字。references/capture.md 包含要執行的流程、狀態矩陣(空的、已填入資料的、錯誤的、緩慢的、離線的、空閒的、隱藏的、條件化的、冷快取和暖快取)、如何捕獲(DevTools HAR、Playwright、捆綁的 scripts/capture.mjs 或應用程式自身的請求日誌),以及如何保持捕獲的可比性。

根據覆蓋圖的計畫選擇流程,而不是根據習慣。如果可以執行,優先使用開發伺服器:其捕獲會命名每個載入的模組,因此地圖可以準確說明哪些懶載入區塊和條件化模組已執行。然後使用捕獲重新執行地圖(步驟 2),並要么捕獲缺口,要么將其列在「限制」下。

捕獲顯示發生了什麼,但從來不顯示為什麼。在僅捕獲的審計中,在每個因果子句出現的地方進行保留(「與兩個查詢鍵一致」、「可能是重新掛載」),而不是在開頭的一次免責聲明中:讀者會引用單個句子,未經修飾的「因為」會帶著其免責聲明一起流傳。

當您擁有的只是一個別人捕獲的檔案時,您無法單獨從捕獲中看出它遺漏了什麼。請說明這一點,列出單次工作階段通常會遺漏的內容(未訪問的路由、未打開的對話框和分頁、標誌和角色變體、錯誤和空狀態、空閒和隱藏分頁行為),並推薦可以補齊這些缺口的捕獲。

python3 <skill-dir>/scripts/har_analyze.py capture.har --format md --out capture.md

它報告每個頁面的 API 請求、每個路徑模板的突發行數、輪詢以及每個金鑰的堆疊計時器數量、視窗內的重複(對於 POST 請求帶有 body 雜湊)、序列鏈、重複的錯誤以及最大的回應。靜態資源被排除;使用 --ignore 忽略遙測主機。

閱讀時需要注意兩點:

  • 對同一個 URL 的兩次 POST 只有在 body 雜湊匹配時才算重複。如果 body 未被捕獲,工具會說「未驗證」;請按此方式報告。
  • 序列鏈僅在後續請求不需要前一個請求的任何內容時才算瀑布流。工具找到形狀;您在程式碼中確認依賴關係。

7. 協調

將每個靜態發現與捕獲證據配對,如果捕獲覆蓋了該畫面。當它們不一致時,捕獲在計數方面勝出,程式碼在原因方面勝出。當捕獲顯示出沒有候選項目可以解釋的放大時,請閱讀程式碼直到可以解釋;這通常是步驟 4 中的金鑰規範性或依賴金鑰問題。

如果儲存庫中有較早的審計報告或效能文件,請針對此提交的程式碼檢查其與您的發現相關的每個聲明,並在報告中列出矛盾之處。過時的聲明是同一錯誤被「修復」兩次的原因。

8. 排名與撰寫

使用評分標準:

嚴重性增長類別典型模式
P0無上限增長:隨著行數、掛載的觀察者數量或時間增長分頁清單上的每行查詢、共用鉤子中的每實例輪詢計時器(SWR、Apollo、自訂)、每次鍵盤按鍵時的失效、未清除的間隔
P1熱門路徑上的固定乘數每個畫面都讀取的清單上 staleTime 為 0、每次焦點時重新擷取、無快取的效果驅動擷取、未綁定的 ...

相關技能