webRequest.onBeforeSendHeaders

此事件在发送任何 HTTP 数据之前触发,但在所有 HTTP 标头可用之后触发。如果您想修改 HTTP 请求标头,这是一个很好的监听位置。

要将请求标头与其余请求数据一起传递到侦听器,请在 extraInfoSpec 数组中传递 "requestHeaders"

要同步修改标头:在 extraInfoSpec 中传递 "blocking",然后在您的事件侦听器中,返回一个具有名为 requestHeaders 的属性的 BlockingResponse,其值为要发送的请求标头集。

要异步修改标头:在 extraInfoSpec 中传递 "blocking",然后在您的事件侦听器中,返回一个 Promise,该 Promise 使用 BlockingResponse 解析。

如果您使用 "blocking",则必须在您的 manifest.json 中拥有 "webRequestBlocking" API 权限

扩展程序可能会在此处发生冲突。如果两个扩展程序对同一个请求监听 onBeforeSendHeaders,则第二个侦听器将看到第一个侦听器所做的修改,并且能够撤消第一个侦听器所做的任何更改。例如,如果第一个侦听器添加了 Cookie 标头,而第二个侦听器剥离了所有 Cookie 标头,则第一个侦听器的修改将丢失。如果您想查看实际发送的标头,而无需担心其他扩展程序随后会更改它们,请使用 onSendHeaders,尽管您无法在此事件上修改标头。

并非所有实际发送的标头都始终包含在 requestHeaders 中。特别是与缓存相关的标头(例如,Cache-ControlIf-Modified-SinceIf-None-Match)永远不会发送。此外,此处的行为可能因浏览器而异。

根据规范,标头名称不区分大小写。这意味着要匹配特定标头,侦听器应在比较之前将名称转换为小写

js
for (const header of e.requestHeaders) {
  if (header.name.toLowerCase() === desiredHeader) {
    // process header
  }
}

浏览器保留由浏览器生成的标头名称的原始大小写。如果扩展程序的侦听器更改了大小写,则不会保留此更改。

语法

js
browser.webRequest.onBeforeSendHeaders.addListener(
  listener,             //  function
  filter,               //  object
  extraInfoSpec         //  optional array of strings
)
browser.webRequest.onBeforeSendHeaders.removeListener(listener)
browser.webRequest.onBeforeSendHeaders.hasListener(listener)

事件具有三个函数

addListener(listener, filter, extraInfoSpec)

向此事件添加侦听器。

removeListener(listener)

停止监听此事件。listener 参数是要移除的侦听器。

hasListener(listener)

检查listener是否已为此事件注册。如果正在监听,则返回true,否则返回false

addListener 语法

参数

listener

当此事件发生时调用的函数。该函数将传递此参数

details

object。请求的详细信息。如果已在extraInfoSpec中包含"requestHeaders",则包括请求标头。有关更多信息,请参阅details部分。

返回值:webRequest.BlockingResponse。如果在extraInfoSpec参数中指定了"blocking",则事件侦听器应返回一个BlockingResponse对象,并可以设置其requestHeaders属性。

filter

webRequest.RequestFilter。一组限制发送到此侦听器的事件的过滤器。

extraInfoSpec 可选

stringarray。事件的其他选项。您可以传递以下任何值

  • "blocking":使请求同步,以便您可以修改请求标头
  • "requestHeaders":将请求标头包含在传递到侦听器的details对象中

其他对象

details

cookieStoreId

string。如果请求来自在上下文标识中打开的标签页,则为上下文标识的 cookie 存储 ID。有关更多信息,请参阅使用上下文标识

documentUrl

string。将加载资源的文档的 URL。例如,如果https://example.com上的网页包含图像或 iframe,则图像或 iframe 的documentUrl将为https://example.com。对于顶级文档,documentUrl未定义。

frameAncestors

array。包含框架层次结构中从子框架到顶级文档的每个文档的信息。数组中的第一个元素包含有关正在请求的文档的直接父级的信息,最后一个元素包含有关顶级文档的信息。如果加载实际上是针对顶级文档,则此数组为空。

url

string。文档从中加载的 URL。

frameId

integer。文档的frameIddetails.frameAncestors[0].frameIddetails.parentFrameId相同。

frameId

integer。如果请求发生在主框架中,则为零;正值是发生请求的子框架的 ID。如果(子)框架的文档已加载(typemain_framesub_frame),则frameId表示此框架的 ID,而不是外部框架的 ID。框架 ID 在一个标签页内是唯一的。

incognito

boolean。请求是否来自隐身窗口。

method

string。标准 HTTP 方法:例如,“GET”或“POST”。

originUrl

string。触发请求的资源的 URL。例如,如果https://example.com包含链接,并且用户单击了该链接,则结果请求的originUrlhttps://example.com

originUrl通常但不总是与documentUrl相同。例如,如果页面包含 iframe,并且 iframe 包含一个将新文档加载到 iframe 中的链接,则结果请求的documentUrl将是 iframe 的父文档,但originUrl将是包含链接的 iframe 中的文档的 URL。

parentFrameId

integer。包含发送请求的框架的框架的 ID。如果不存在父框架,则设置为 -1。

proxyInfo

object。此属性仅在请求被代理时存在。它包含以下属性

host

string。代理服务器的主机名。

port

integer。代理服务器的端口号。

type

string。代理服务器的类型。以下之一:

  • "http": HTTP 代理(或 HTTPS 的 SSL CONNECT)
  • "https": 通过 TLS 连接到代理的 HTTP 代理
  • "socks": SOCKS v5 代理
  • "socks4": SOCKS v4 代理
  • "direct": 无代理
  • "unknown": 未知代理
username

string。代理服务的用户名。

proxyDNS

boolean。如果代理将根据提供的主机名执行域名解析,则为 true,这意味着客户端不应执行自己的 DNS 查找。

failoverTimeout

integer。故障转移超时(秒)。如果代理连接失败,则在此期间内不再使用该代理。

requestHeaders 可选

webRequest.HttpHeaders。将与此请求一起发送的 HTTP 请求头。

requestId

string。请求的 ID。请求 ID 在浏览器会话中是唯一的,因此您可以使用它们来关联与同一请求关联的不同事件。

tabId

integer。发生请求的标签页的 ID。如果请求与标签页无关,则设置为 -1。

thirdParty

boolean。指示请求及其内容窗口层次结构是否为第三方。

timeStamp

number。此事件触发的时刻,以自纪元以来的毫秒数表示。

type

webRequest.ResourceType。正在请求的资源类型:例如,“image”、“script”、“stylesheet”。

url

string。请求的目标。

urlClassification

object。如果请求被Firefox 跟踪保护分类,则与请求关联的跟踪类型。这是一个具有以下属性的对象

firstParty

array of strings。请求的第一方的分类标志。

thirdParty

array of strings。请求或其窗口层次结构的第三方的分类标志。

分类标志包括

  • fingerprintingfingerprinting_content:表示请求参与了指纹识别(“发现了一个进行指纹识别的来源”)。
    • fingerprinting 表示该域名属于指纹识别和跟踪类别。此类域名的示例包括希望将个人资料与访问用户关联的广告客户。
    • fingerprinting_content 表示该域名属于指纹识别类别,但不属于跟踪类别。此类域名的示例包括使用指纹识别技术识别访问用户以进行反欺诈的支付提供商。
  • cryptominingcryptomining_content:类似于指纹识别类别,但用于加密挖掘资源。
  • trackingtracking_adtracking_analyticstracking_socialtracking_content:表示请求参与了跟踪。tracking 是任何通用跟踪请求,adanalyticssocialcontent 后缀标识跟踪器的类型。
  • any_basic_tracking:一个元标志,它组合了跟踪和指纹识别标志,不包括 tracking_contentfingerprinting_content
  • any_strict_tracking:一个元标志,它组合了所有跟踪和指纹识别标志。
  • any_social_tracking:一个元标志,它组合了所有社交跟踪标志。

浏览器兼容性

BCD 表格仅在启用 JavaScript 的浏览器中加载。

示例

此代码更改了“User-Agent”标头,以便浏览器将自身识别为 Opera 12.16,但仅在访问 https://httpbin.org/ 下的页面时。

js
"use strict";

/*
This is the page for which we want to rewrite the User-Agent header.
*/
const targetPage = "https://httpbin.org/*";

/*
Set UA string to Opera 12
*/
const ua =
  "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16";

/*
Rewrite the User-Agent header to "ua".
*/
function rewriteUserAgentHeader(e) {
  for (const header of e.requestHeaders) {
    if (header.name.toLowerCase() === "user-agent") {
      header.value = ua;
    }
  }
  return { requestHeaders: e.requestHeaders };
}

/*
Add rewriteUserAgentHeader as a listener to onBeforeSendHeaders,
only for the target page.

Make it "blocking" so we can modify the headers.
*/
browser.webRequest.onBeforeSendHeaders.addListener(
  rewriteUserAgentHeader,
  { urls: [targetPage] },
  ["blocking", "requestHeaders"],
);

此代码与前面的示例完全相同,只是侦听器是异步的,返回一个Promise,该 Promise 使用新的标头解析。

js
"use strict";

/*
This is the page for which we want to rewrite the User-Agent header.
*/
const targetPage = "https://httpbin.org/*";

/*
Set UA string to Opera 12
*/
const ua =
  "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16";

/*
Rewrite the User-Agent header to "ua".
*/
function rewriteUserAgentHeaderAsync(e) {
  const asyncRewrite = new Promise((resolve, reject) => {
    setTimeout(() => {
      for (const header of e.requestHeaders) {
        if (header.name.toLowerCase() === "user-agent") {
          header.value = ua;
        }
      }
      resolve({ requestHeaders: e.requestHeaders });
    }, 2000);
  });

  return asyncRewrite;
}

/*
Add rewriteUserAgentHeader as a listener to onBeforeSendHeaders,
only for the target page.

Make it "blocking" so we can modify the headers.
*/
browser.webRequest.onBeforeSendHeaders.addListener(
  rewriteUserAgentHeaderAsync,
  { urls: [targetPage] },
  ["blocking", "requestHeaders"],
);

扩展示例

注意:此 API 基于 Chromium 的 chrome.webRequest API。本文档源自 Chromium 代码中的 web_request.json