要创建一个可以灵活修改HTTP请求头的Chrome扩展,包括一个用户界面来动态设置头部名称和值,可以按照以下步骤进行。我们会用到 chrome.storage API 来保存用户的设置,并在后台脚本中使用这些设置来修改请求头。
文件结构
my_chrome_extension/
│
├── icons/
│ ├── icon16.png
│ ├── icon48.png
│ └── icon128.png
│
├── background.js
├── manifest.json
├── options.html
├── options.js
├── popup.html
├── popup.js
├── popup.css
manifest.json
{
"manifest_version": 2,
"name": "Flexible HTTP Headers Modifier",
"version": "1.0",
"description": "A Chrome extension to modify HTTP headers with user-defined values",
"permissions": [
"storage",
"webRequest",
"webRequestBlocking",
"<all_urls>"
],
"background": {
"scripts": ["background.js"]
},
"options_page": "options.html",
"browser_action": {
"default_popup": "popup.html",
"default_icon": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
},
"icons": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
}
background.js
let customHeaders = {};
chrome.runtime.onInstalled.addListener(() => {
// Load headers from storage when the extension is installed or updated
chrome.storage.sync.get(['headers'], function(result) {
if (result.headers) {
customHeaders = result.headers;
}
});
});
chrome.webRequest.onBeforeSendHeaders.addListener(
function(details) {
// Modify request headers
for (const [name, value] of Object.entries(customHeaders)) {
let headerExists = false;
for (let header of details.requestHeaders) {
if (header.name.toLowerCase() === name.toLowerCase()) {
header.value = value;
headerExists = true;
break;
}
}
if (!headerExists) {
details.requestHeaders.push({ name: name, value: value });
}
}
return { requestHeaders: details.requestHeaders };
},
{ urls: ["<all_urls>"] },
["blocking", "requestHeaders"]
);
chrome.storage.onChanged.addListener(function(changes, namespace) {
if (namespace === 'sync' && changes.headers) {
customHeaders = changes.headers.newValue;
}
});
options.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Extension Options</title>
<link rel="stylesheet" href="popup.css">
</head>
<body>
<h1>Modify HTTP Headers</h1>
<div id="headers-container">
<div class="header-entry">
<input type="text" placeholder="Header Name" class="header-name">
<input type="text" placeholder="Header Value" class="header-value">
<button class="remove-header">Remove</button>
</div>
</div>
<button id="add-header">Add Header</button>
<button id="save-headers">Save Headers</button>
<script src="options.js"></script>
</body>
</html>
options.js
document.addEventListener('DOMContentLoaded', function() {
const headersContainer = document.getElementById('headers-container');
const addHeaderButton = document.getElementById('add-header');
const saveHeadersButton = document.getElementById('save-headers');
addHeaderButton.addEventListener('click', function() {
const headerEntry = document.createElement('div');
headerEntry.className = 'header-entry';
headerEntry.innerHTML = `
<input type="text" placeholder="Header Name" class="header-name">
<input type="text" placeholder="Header Value" class="header-value">
<button class="remove-header">Remove</button>
`;
headerEntry.querySelector('.remove-header').addEventListener('click', function() {
headerEntry.remove();
});
headersContainer.appendChild(headerEntry);
});
saveHeadersButton.addEventListener('click', function() {
const headers = {};
document.querySelectorAll('.header-entry').forEach(entry => {
const name = entry.querySelector('.header-name').value;
const value = entry.querySelector('.header-value').value;
if (name && value) {
headers[name] = value;
}
});
chrome.storage.sync.set({headers: headers}, function() {
alert('Headers saved');
});
});
// Load saved headers on options page load
chrome.storage.sync.get(['headers'], function(result) {
if (result.headers) {
for (const [name, value] of Object.entries(result.headers)) {
const headerEntry = document.createElement('div');
headerEntry.className = 'header-entry';
headerEntry.innerHTML = `
<input type="text" value="${name}" class="header-name">
<input type="text" value="${value}" class="header-value">
<button class="remove-header">Remove</button>
`;
headerEntry.querySelector('.remove-header').addEventListener('click', function() {
headerEntry.remove();
});
headersContainer.appendChild(headerEntry);
}
}
});
});
popup.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Popup</title>
<link rel="stylesheet" href="popup.css">
</head>
<body>
<h1>Modify HTTP Headers</h1>
<button id="open-options">Open Options</button>
<script src="popup.js"></script>
</body>
</html>
popup.js
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('open-options').addEventListener('click', function() {
chrome.runtime.openOptionsPage();
});
});
popup.css
body {
width: 200px;
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
box-sizing: border-box;
}
h1 {
font-size: 16px;
margin: 0 0 20px;
text-align: center;
}
button {
display: block;
width: 100%;
margin: 10px 0;
padding: 10px;
font-size: 14px;
cursor: pointer;
}
加载和测试扩展
- 打开 Chrome 浏览器。
- 进入
chrome://extensions/
页面。 - 打开右上角的“开发者模式”。
- 点击“加载已解压的扩展程序”按钮。
- 选择你的扩展所在的目录
my_chrome_extension
。
现在,你可以通过扩展的图标打开选项页面,添加或移除请求头。保存后,这些头会在所有的HTTP请求(包括AJAX请求)中被修改。
让我们详细解释一下这段 background.js 代码及其功能。
好的,让我们详细解释一下这段 background.js
代码及其功能。
代码解释
let customHeaders = {};
// 当扩展程序安装或更新时加载存储的headers
chrome.runtime.onInstalled.addListener(() => {
chrome.storage.sync.get(['headers'], function(result) {
if (result.headers) {
customHeaders = result.headers;
}
});
});
// 拦截并修改请求头
chrome.webRequest.onBeforeSendHeaders.addListener(
function(details) {
// 修改请求头
for (const [name, value] of Object.entries(customHeaders)) {
let headerExists = false;
for (let header of details.requestHeaders) {
if (header.name.toLowerCase() === name.toLowerCase()) {
header.value = value;
headerExists = true;
break;
}
}
if (!headerExists) {
details.requestHeaders.push({ name: name, value: value });
}
}
return { requestHeaders: details.requestHeaders };
},
{ urls: ["<all_urls>"] },
["blocking", "requestHeaders"]
);
// 监听存储的变化
chrome.storage.onChanged.addListener(function(changes, namespace) {
if (namespace === 'sync' && changes.headers) {
customHeaders = changes.headers.newValue;
}
});
详细解释
-
定义自定义请求头变量:
let customHeaders = {};
定义一个空对象
customHeaders
来存储用户定义的自定义请求头。 -
扩展程序安装或更新时加载存储的请求头:
chrome.runtime.onInstalled.addListener(() => { chrome.storage.sync.get(['headers'], function(result) { if (result.headers) { customHeaders = result.headers; } }); });
当 Chrome 扩展程序安装或更新时,会触发
chrome.runtime.onInstalled
事件。此时,从chrome.storage.sync
中获取存储的headers
并将其赋值给customHeaders
。chrome.storage.sync
是一个同步存储,可以在不同设备之间同步数据。 -
拦截并修改请求头:
chrome.webRequest.onBeforeSendHeaders.addListener( function(details) {
使用
chrome.webRequest.onBeforeSendHeaders.addListener
方法拦截每个 HTTP 请求。 -
修改请求头:
for (const [name, value] of Object.entries(customHeaders)) { let headerExists = false; for (let header of details.requestHeaders) { if (header.name.toLowerCase() === name.toLowerCase()) { header.value = value; headerExists = true; break; } } if (!headerExists) { details.requestHeaders.push({ name: name, value: value }); } }
遍历
customHeaders
中的每个自定义请求头:- 如果在
details.requestHeaders
中找到相同名称的请求头,则修改其值。 - 如果未找到相同名称的请求头,则添加新的请求头。
- 如果在
-
返回修改后的请求头:
return { requestHeaders: details.requestHeaders };
返回修改后的请求头,确保新的请求头会被应用到实际的 HTTP 请求中。
-
监听存储变化:
chrome.storage.onChanged.addListener(function(changes, namespace) { if (namespace === 'sync' && changes.headers) { customHeaders = changes.headers.newValue; } });
监听
chrome.storage
的变化,当headers
发生变化时,更新customHeaders
。这使得用户可以通过扩展程序界面动态地修改自定义请求头,而不需要重新加载插件。
为什么要这么写
-
自定义请求头存储与同步:
- 通过
chrome.storage.sync
存储自定义请求头,使其可以在不同设备之间同步。 - 在扩展程序安装或更新时加载存储的请求头,确保扩展程序启动时使用最新的自定义请求头。
- 通过
-
拦截和修改请求头:
- 使用
chrome.webRequest.onBeforeSendHeaders
拦截每个 HTTP 请求,并在请求发送之前修改请求头,实现灵活的请求头修改。
- 使用
-
动态更新自定义请求头:
- 监听
chrome.storage.onChanged
事件,实时更新customHeaders
,使得用户可以动态地修改请求头,而不需要重新加载插件。
- 监听
通过这种方式,用户可以在扩展程序界面灵活地设置和修改 HTTP 请求头,适用于各种不同的需求,且这些设置可以在不同设备之间同步。