最简单的浏览器插件,包括manifest.json、background.js两个文件,跟页面交互则需要content-script.js,给用户展示一个页面,则需要popup.html。本文的目标是开发一个浏览器插件来实现对请求头的修改。
一、manifest.json
首先,需要使用manifest.json来做一个元数据的录入和文件引入等操作:
{
"name": "header增加器",
"version": "1.0.1",
"manifest_version": 3,
"description": "header增加器",
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content-script.js"],
"run_at": "document_start"
}
],
"permissions": [
"declarativeNetRequest",
"declarativeNetRequestWithHostAccess",
"declarativeNetRequestFeedback",
"storage"
],
"host_permissions": ["*://*/*"]
}
此处,Chrome插件的manifest.json
文件定义了插件的基本信息、背景脚本、内容脚本、权限以及宿主权限。下面是对这个文件的详细讲解:
基本信息
name
: 插件的名称,这里是“header增加器”。version
: 插件的版本号,这里是1.0.1
。manifest_version
: 清单文件的版本号,Chrome扩展使用版本号来控制API的向后兼容性。这里使用的是3
,表示该扩展使用了Chrome扩展平台的一些较新功能。description
: 插件的简短描述,这里简单重复了插件的名称。
背景脚本
background
: 指定了扩展的背景脚本,它是扩展的持久性、全局性的脚本。在这个例子中,它指向了一个名为background.js
的Service Worker文件。背景脚本可以在扩展的生命周期内持续运行,并且可以监听来自Chrome浏览器的事件,执行长时间运行的任务等。
内容脚本
content_scripts
: 定义了一个或多个内容脚本的数组,内容脚本会在匹配的页面内注入并执行。matches
: 指定了内容脚本将注入的页面URL模式。这里的"<all_urls>"
表示内容脚本会注入到所有打开的网页中。js
: 指定了内容脚本的JavaScript文件列表。这里只有一个文件content-script.js
。run_at
: 指定了内容脚本注入页面的时机。document_start
表示在文档开始解析时立即注入脚本,这允许脚本在DOM构建之前运行,可以修改或阻止某些元素的加载。
权限
permissions
: 指定了扩展需要的权限列表。这些权限允许扩展执行某些操作或访问某些资源。declarativeNetRequest
和declarativeNetRequestWithHostAccess
: 允许扩展使用声明式网络请求API,该API允许扩展以声明方式控制网络请求,如修改请求头、重定向请求等。declarativeNetRequestWithHostAccess
提供了更高级的功能,允许扩展指定哪些宿主可以访问哪些网络请求。declarativeNetRequestFeedback
: 允许扩展收集用户对声明式网络请求规则的反馈。storage
: 允许扩展访问浏览器的存储API,如localStorage、sessionStorage等。
宿主权限
host_permissions
: 指定了扩展可以访问的URL模式。这里的"*://*/*"
表示扩展可以访问所有URL。这是为了确保扩展能够对其内容脚本注入的页面进行必要的操作。
总结来说,这个Chrome插件的manifest.json
文件定义了一个名为“header增加器”的扩展,它通过内容脚本在所有页面上注入content-script.js
,并使用背景脚本(background.js
)来执行一些全局性任务。扩展具有修改网络请求、收集用户反馈和访问浏览器存储的权限,并且可以访问所有URL。
二、background.js
function parseStringToObject(str) {
const result = []
const pairs = str.split(';');
pairs.forEach(pair => {
const obj = {};
const [key, value] = pair.split(':');
obj["header"] = key;
obj["operation"] = "set";
obj["value"] = value;
result.push(obj);
});
return result;
}
function Init() {
// var customHeaders = []
chrome.storage.local.get("customHeaders", (result)=> {
if (result.customHeaders) {
console.log(result.customHeaders);
const customHeaders = parseStringToObject(result.customHeaders)
= const initialRules = [
{
id: 1,
priority: 1,
action: {
type: "modifyHeaders",
requestHeaders: customHeaders
},
condition: {
// resourceTypes: ["main_frame", "xmlhttprequest"]
excludedResourceTypes: ["ping"]
}
},
];
chrome.declarativeNetRequest.getDynamicRules(function (res) {
let rules = res.map((e) => e.id);
chrome.declarativeNetRequest.updateDynamicRules(
{
addRules: initialRules,
removeRuleIds: rules,
},
function (callback) {}
);
});
}
})
}
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
Init();
});
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
if (request.action == "modifyHeaders") {
chrome.storage.local.set({
customHeaders: request.customHeaders
}, function() {
console.log('数据已存储');
});
Init()
}
return true;
});
在这个文件中,我们定义了这个插件的后台工作,使用2个linstener来监听事件来触发Init(),在Init()中,我们通过从localStorage中获取指定的字段,拿到这个定义好结构的字段进行解析插入chrome.declarativeNetRequest中,进而改变请求头。
三、content-script.js
window.addEventListener("message", (event) => {
if (event.data.code == "mhv3-customHeaders") {
var customHeaders = localStorage.getItem("customHeaders");
chrome.runtime.sendMessage(
{
action: "modifyHeaders",
customHeaders: customHeaders
},
(res) => {
console.log(res)
}
);
}
});
这个文件中我们定义了插件和用户页面内容之间的交互,从而响应用户的操作,本示例中,content-script.js接收一个window的event,在指定的event类型中,向background.js中sendMessage,从而形成前后端的通信。
四、使用
将以上三个文件放到一个文件夹,浏览器插件页面打开开发者模式,加载已经解压缩的插件,即可加载此插件,加载插件后,在打开页面中输入内容:
localStorage.setItem('customHeaders', 'Authorization:123456778);
window.postMessage({ cmd: "invoke", code: "mhv3-customHeaders" }, "*");
即可在浏览器的每个请求中加入一个请求头:Authorization: 123456778