Javascript Browser WebExtension API - 获取活动选项卡的所有 headers 和其他参数

Javascript Browser WebExtension API - Get all headers and other parameters of the active tab

由于我是 javascript 的新手,我正在为浏览器开发一个简单的练习插件,并且我正在阅读 https://developer.mozilla.org/en-US/docs/Web/API

与该主题相关的文档

我的目的是能够在我正在创建的上下文菜单中复制浏览器开发工具中网络选项卡的“复制为 cURL”。

例如,如果我考虑 https://whosebug.com(使用 Firefox 91.5.0esr(64 位))的“复制为 cURL”命令:

curl 'https://whosebug.com/' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'Accept-Language: en-US,en;q=0.5' --compressed -H 'Referer: https://www.google.com/' -H 'Connection: keep-alive' -H 'Cookie: prov=d03ecfc2-207d-cda2-bb6b-38b282cd5b84; _ga=GA1.2.1551734572.1648346036; _gid=GA1.2.1710305938.1648346036; _gat=1' -H 'Upgrade-Insecure-Requests: 1' -H 'Sec-Fetch-Dest: document' -H 'Sec-Fetch-Mode: navigate' -H 'Sec-Fetch-Site: cross-site' -H 'Sec-Fetch-User: ?1' -H 'Cache-Control: max-age=0' -H 'TE: trailers'

我能够获取 Cookie 值,但不能获取其他 headers 或任何其他参数(即 POST 数据参数)。到目前为止,我的代码如下:

script.js

/*
Called when the item has been created, or when creation failed due to an error.
We'll just log success/failure here.
*/
function onCreated() {
  if (browser.runtime.lastError) {
    console.log(`Error: ${browser.runtime.lastError}`);
  } else {
    console.log("Item created successfully");
  }
}

/*
Called when the item has been removed.
We'll just log success here.
*/
function onRemoved() {
  console.log("Item removed successfully");
}

/*
Called when there was an error.
We'll just log the error here.
*/
function onError(error) {
  console.log(`Error: ${error}`);
}

/*
Create all the context menu items.
*/

browser.menus.create({
  id: "tools-copy",
  title: browser.i18n.getMessage("menuItemToolsCopy"),
  contexts: ["all"],
}, onCreated);

browser.menus.create({
  id: "tools-copy-as-cURL-example",
  parentId: "tools-copy",
  type: "radio",
  title: browser.i18n.getMessage("menuItemToolsCopyAsCURL"),
  contexts: ["all"],
  checked: false
}, onCreated);

/*
functions to impl
*/

function updateClipboard(newClip) {
  navigator.clipboard.writeText(newClip).then(function() {
    /* clipboard successfully set */
  }, function() {
    /* clipboard write failed */
  });
}

//get active tab to run an callback function.
//it sends to our callback an array of tab objects
function getActiveTab() {
  return browser.tabs.query({currentWindow: true, active: true});
}

function showCookiesForTab(tabs) {
  //get the first tab object in the array
  let tab = tabs.pop();

  //get all cookies in the domain
  var gettingAllCookies = browser.cookies.getAll({url: tab.url});
  var str_cookies = "";

  gettingAllCookies.then((cookies) => {
    if (cookies.length > 0) {
      str_cookies = "-H 'Cookie: ";
      for (let cookie of cookies) {
        str_cookies = str_cookies.concat(cookie.name + "="+ cookie.value+"; ");
      }
      str_cookies = str_cookies.replace(/.{0,2}$/,"'");
      console.log(str_cookies);
    }
  });
}

/*
The click event listener, where we perform the appropriate action given the
ID of the menu item that was clicked.
*/
browser.menus.onClicked.addListener((info, tab) => {
  switch (info.menuItemId) {    
    case "tools-copy-as-cURL-example":
      getActiveTab().then(showCookiesForTab);
      break;
  }
});

message.json

{  
  "extensionName": {
    "message": "Copy as cURL demo",
    "description": "Name of the extension."
  },

  "extensionDescription": {
    "message": "Demonstrates the menus API for copying cURL.",
    "description": "Description of the add-on."
  },

  "menuItemToolsCopy": {
    "message": "Copy",
    "description": "Title of tools copy item."
  },

  "menuItemToolsCopyAsCURL": {
    "message": "Copy as cURL",
    "description": "Title of cURL copy item."
  }
}

manifest.json

{
  "manifest_version": 2,
  "name": "__MSG_extensionName__",
  "description": "__MSG_extensionDescription__",
  "version": "1.0",
  "default_locale": "en",
  "browser_specific_settings": {
    "gecko": {
      "strict_min_version": "56.0a1"
    }
  },

  "background": {
    "scripts": ["script.js"]
  },
  
  "permissions": [
    "menus",
    "activeTab",
    "cookies",
    "webRequest",
    "<all_urls>",
    "tabs",
    "clipboardWrite"
  ]
}

根据文档,我尝试使用此 object 数组 https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webRequest/HttpHeaders 以及 browser.webRequest.onHeadersReceived.addListener() 但没有成功。

我的目的只是阅读浏览器当前活动标签页的headers。我不需要编辑它们。

如何获取所有 headers 和任何数据参数(在 POST 请求的情况下)? 对于这些简单的请求,我很抱歉,我是这个主题的新手。

提前谢谢你。

无法追溯获取选项卡的此信息,因此您必须不断观察网络并将每个选项卡 ID 和框架 ID 的数据存储在全局对象中以支持框架。

const tabData = {};
const getProp = (obj, key) => (obj[key] || (obj[key] = {}));
const encodeBody = body => 'implement it yourself';

const FILTER = {
  types: ['main_frame', 'sub_frame'],
  urls: ['<all_urls>'],
};

browser.webRequest.onBeforeRequest.addListener(e => {
  getProp(getProp(tabData, e.tabId), e.frameId).body = e.requestBody;
}, FILTER, ['requestBody']);

browser.webRequest.onSendHeaders.addListener(e => {
  getProp(getProp(tabData, e.tabId), e.frameId).headers = e.requestHeaders;
}, FILTER, ['requestHeaders']);

browser.tabs.onRemoved.addListener(tabId => delete tabData[tabId]);

browser.tabs.onReplaced.addListener((addId, delId) => delete tabData[delId]);

browser.menus.onClicked.addListener((info, tab) => {
  if (info.menuItemId === 'tools-copy-as-cURL-example') {
    const data = tabData[tab.id]?.[info.frameId || 0] || {};
    navigator.clipboard.writeText(`curl '${info.frameUrl || tab.url}'` +
      (data.headers?.map(h => ` -H '${h.name}: ${h.value}'`).join('') || '') +
      (data.body ? ' ' + encodeBody(data.body) : ''));
  }
});