攔截 HTTP 請求

要攔截 HTTP 請求,請使用 webRequest API。此 API 允許您為 HTTP 請求的各個階段新增監聽器。在監聽器中,您可以

  • 訪問請求頭、請求體和響應頭。
  • 取消和重定向請求。
  • 修改請求頭和響應頭。

本文將介紹 webRequest 模組的三個不同用途:

  • 在發出請求時記錄請求 URL。
  • 重定向請求。
  • 修改請求頭。

記錄請求 URL

要檢視如何使用 webRequest 記錄請求,請建立一個名為 "requests" 的新目錄。在該目錄中,建立一個名為 "manifest.json" 的檔案並新增

json
{
  "description": "Demonstrating webRequests",
  "manifest_version": 2,
  "name": "webRequest-demo",
  "version": "1.0",

  "permissions": ["webRequest", "<all_urls>"],

  "background": {
    "scripts": ["background.js"]
  }
}

接下來,建立一個名為 "background.js" 的檔案並新增

js
function logURL(requestDetails) {
  console.log(`Loading: ${requestDetails.url}`);
}

browser.webRequest.onBeforeRequest.addListener(logURL, {
  urls: ["<all_urls>"],
});

您使用 onBeforeRequest 在請求開始前呼叫 logURL() 函式。logURL() 函式從事件物件中獲取請求的 URL 並將其記錄到瀏覽器控制檯中。{urls: ["<all_urls>"]} 模式表示您攔截所有 URL 的 HTTP 請求。

要進行測試

在瀏覽器控制檯中,您應該能看到瀏覽器請求的任何資源的 URL。例如,此截圖顯示了載入維基百科頁面時的 URL。

Browser console menu: URLs from extension

重定向請求

現在使用 webRequest 重定向 HTTP 請求。首先,將 "manifest.json" 替換為以下內容:

json
{
  "description": "Demonstrating webRequests",
  "manifest_version": 2,
  "name": "webRequest-demo",
  "version": "1.0",

  "permissions": [
    "webRequest",
    "webRequestBlocking",
    "https://mdn.club.tw/"
  ],

  "background": {
    "scripts": ["background.js"]
  }
}

這裡的更改:

  • 新增 webRequestBlocking 許可權。當擴充套件需要修改請求時,需要此額外許可權。
  • <all_urls> 許可權替換為單獨的 主機許可權,這是最小化請求許可權數量的最佳實踐。

接下來,將 "background.js" 替換為以下內容:

js
let pattern = "https://mdn.club.tw/*";
const targetUrl =
  "https://mdn.club.tw/en-US/docs/Mozilla/Add-ons/WebExtensions/Your_second_WebExtension/frog.jpg";

function redirect(requestDetails) {
  console.log(`Redirecting: ${requestDetails.url}`);
  if (requestDetails.url === targetUrl) {
    return;
  }
  return {
    redirectUrl: targetUrl,
  };
}

browser.webRequest.onBeforeRequest.addListener(
  redirect,
  { urls: [pattern], types: ["image"] },
  ["blocking"],
);

同樣,您使用 onBeforeRequest 事件監聽器在每次請求傳送前執行一個函式。此函式將 redirectUrl 替換為函式中指定的目標 URL。在本例中,是從 您的第二個擴充套件教程中的青蛙圖片。

這次您沒有攔截每個請求:{urls:[pattern], types:["image"]} 選項指定您只攔截 (1) 位於 "https://mdn.club.tw/" 下的 URL 和 (2) 圖片資源的請求。有關更多資訊,請參閱 webRequest.RequestFilter

另外,請注意您傳遞了一個名為 "blocking" 的選項:只要您想修改請求,就必須傳遞此選項。它使監聽器函式阻塞網路請求,因此瀏覽器在繼續之前會等待監聽器返回。有關 "blocking" 的更多資訊,請參閱 webRequest.onBeforeRequest 文件。

要進行測試,請開啟 MDN 上包含圖片的頁面(例如,列出擴充套件使用者介面元件的頁面),重新載入擴充套件,然後重新載入 MDN 頁面。您會看到類似這樣的內容:

Images on a page replaced with a frog image

修改請求頭

最後,使用 webRequest 修改請求頭。在此示例中,您將 "User-Agent" 頭更改為使瀏覽器標識自己為 Opera 12.16,但僅當訪問 "https://useragentstring.com/" 下的頁面時。

更新 "manifest.json" 以包含 https://useragentstring.com/,如下所示:

json
{
  "description": "Demonstrating webRequests",
  "manifest_version": 2,
  "name": "webRequest-demo",
  "version": "1.0",

  "permissions": [
    "webRequest",
    "webRequestBlocking",
    "https://useragentstring.com/"
  ],

  "background": {
    "scripts": ["background.js"]
  }
}

將 "background.js" 替換為類似這樣的程式碼:

js
let targetPage = "https://useragentstring.com/*";

let ua =
  "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16";

function rewriteUserAgentHeader(e) {
  e.requestHeaders.forEach((header) => {
    if (header.name.toLowerCase() === "user-agent") {
      header.value = ua;
    }
  });
  return { requestHeaders: e.requestHeaders };
}

browser.webRequest.onBeforeSendHeaders.addListener(
  rewriteUserAgentHeader,
  { urls: [targetPage] },
  ["blocking", "requestHeaders"],
);

您使用 onBeforeSendHeaders 事件監聽器,在傳送請求頭之前執行一個函式。

僅當請求 URL 匹配 targetPage 模式時,才會呼叫監聽器函式。另外,請注意您再次將 "blocking" 作為選項傳遞。您還傳遞了 "requestHeaders",這意味著監聽器會收到一個包含您期望傳送的請求頭的陣列。有關這些選項的更多資訊,請參閱 webRequest.onBeforeSendHeaders

監聽器函式在請求頭陣列中查詢 "User-Agent" 頭,將其值替換為 ua 變數的值,然後返回修改後的陣列。這個修改後的陣列將被髮送到伺服器。

要進行測試,請開啟 useragentstring.com 並檢查它是否將瀏覽器識別為 Firefox。然後重新載入擴充套件,重新載入 useragentstring.com,您會看到 Firefox 現在被識別為 Opera。

useragentstring.com showing details of the modified user agent string

瞭解更多

要了解使用 webRequest API 可以完成的所有工作,請參閱其 參考文件