跳轉到主要內容
用 declarativeNetRequest API 打造一個 adblocker(也寫作 ad blocker 或 content blocker)。你宣告比對規則,瀏覽器就會在請求離開網路堆疊前原生封鎖它們。

你會做出什麼

為什麼 MV3 取代了阻斷式 webRequest

Manifest V2 的廣告封鎖器註冊阻斷式 webRequest 監聽器。每個請求都要暫停,等擴充功能的 JavaScript 決定它的命運。Manifest V3 基於效能與隱私因素移除了這個模型。改用 declarativeNetRequest 後,瀏覽器自己評估你的規則。你的程式碼從不佔據請求路徑,也從不為了封鎖而讀取請求內容。 代理式的使用情境,例如把所有流量導向另一台伺服器,請改用 proxy API 而不是請求規則。

Manifest

封鎖與允許規則不需要 host permissions。重新導向規則與標頭規則需要受影響網站的 host permissions。
manifest.json
Extension.js 會編譯 rule_resources 引用的規則集檔案,並隨建置輸出一起發出。

靜態規則

靜態規則放在 rules.json,會在擴充功能載入時載入。
rules.json
||domain^ 過濾語法會比對一個網域及其所有子網域。

封鎖整個頁面

在 resourceTypes 裡寫上 main_frame 的規則會封鎖頂層導覽,而不只是子資源:
rules.json
兩個瀏覽器的表現不同,但都代表規則生效了:
  • Chrome 會把分頁換成它自己的封鎖頁,顯示 “This page has been blocked by an extension” 與代碼 ERR_BLOCKED_BY_CLIENT。主控台裡沒有任何輸出。
  • Firefox 會取消這次導覽,分頁保留先前的頁面。沒有錯誤頁,也沒有主控台項目。
Extension.js 會把規則檔複製到 dist/<browser>/declarative_net_request/ 並改寫 manifest 裡的路徑,所以依上面 manifest 的寫法引用它即可。
本節與下一節的行為是在 Chrome 155 與 Firefox 158 上、使用 Extension.js 4.1.33 量測的。

把被封鎖的頁面重新導向到擴充功能內的頁面

把 block 動作換成 redirect,指向隨擴充功能一起出貨的頁面:
rules.json
把頁面放在 public/blocked.html。Extension.js 會把 public/ 複製到輸出根目錄,所以 /blocked.html 不必在 manifest 裡登記就能解析。 重新導向需要的權限比封鎖多,而且兩個瀏覽器不一樣:
  • Chrome 需要涵蓋該網站的主機權限。沒有它,規則就是靜默的空操作:頁面正常載入,規則集仍顯示已啟用,主控台裡什麼都沒有。對於指向擴充功能頁面的 main_frame 重新導向,Chrome 不需要 web_accessible_resources。
  • Firefox 既需要主機權限,也需要把頁面列進 web_accessible_resources。缺少 web_accessible_resources 項目時,導覽會以 NS_ERROR_DOM_BAD_URI 失敗,分頁停在原處。缺少主機權限時則和 Chrome 一樣是靜默的空操作。
action 範本把 Firefox 建置為 Manifest V2,那裡的主機權限寫在 permissions 中,web_accessible_resources 是字串清單。帶前綴的鍵會在其目標上取代同名的一般鍵,所以 Firefox 的清單要再寫一次 declarativeNetRequest。藉由瀏覽器專屬欄位,一份 manifest 同時涵蓋兩個瀏覽器:
manifest.json
如果你的專案也把 Firefox 建置為 Manifest V3,拿掉 firefox: 鍵,在一般的 web_accessible_resources 下使用物件形式 [{ "resources": ["blocked.html"], "matches": ["<all_urls>"] }]。兩個瀏覽器都接受。

動態規則

動態規則用於在執行階段變動的過濾條件,例如使用者自行加入的封鎖清單項目。重新加入規則前先移除該規則 id,讓更新保持冪等。
background.js
Chrome 對靜態與動態規則的數量有上限。在發佈大型過濾清單前,先到 declarativeNetRequest 參考文件確認目前的限制。

在徽章上統計已封鎖的請求

一個呼叫就能把 action 徽章變成各分頁的規則命中計數器。
background.js
要用 getMatchedRules 自行讀取命中的規則,需加上 declarativeNetRequestFeedback 權限。

執行

在編輯 manifest.json 之前,先知道 manifest 變更需要重新啟動開發伺服器。參考 開發更新行為。
開啟一個會請求被封鎖網域的頁面。規則命中時,徽章數字會上升。

Firefox 注意事項

  • Firefox 在 Manifest V3 支援 declarativeNetRequest。
  • Firefox 不支援 setExtensionActionOptions,因此徽章計數器僅限 Chromium。
  • Firefox 在 Manifest V3 仍允許阻斷式 webRequest,Chrome 則把它保留給政策安裝。
  • 當兩個目標出現分歧時,使用 瀏覽器專屬 manifest 欄位。

從範本開始

action 範本附帶一個 background script 加上工具列 popup,是封鎖器 UI 的好基礎。
儲存庫:extension-js/examples/action

最佳實務

  • 靜態規則放在 rules.json,動態規則保留給使用者的選擇。
  • 給每個動態規則一個穩定的 id,讓移除保持可預期。
  • 把 resourceTypes 限定在你要封鎖的類型,而不是所有類型。
  • 優先使用封鎖與允許規則,它們不需要 host permissions。
  • 在發佈過濾條件更新前,用真實頁面測試規則。

後續步驟