1
浏览器插件:那些你需会的操作
发布于: 2020 年 11 月 15 日
Chrome 扩展程序序列文章:
1、 配置文件(manifest.json)详解
{
"manifest_version": 2, // manifest文件版本号。Chrome18开始必须为2
"page_action": {}, // 地址栏右侧图标管理。包含图标及页面设置等
"theme": {}, // 用于更改整改浏览器的主题
"app": {}, // 指定扩展需要跳转到的URL
"background":{}, // 指定扩展进程的background运行环境
"chrome_url_overrides":{ // 替换页面,将原定显示的页面替换为自定义页面
"pageToOverride":"", // 页面
"bookmarks":"", // 书签
"history":"", // 历史
"newtab":"" // 新标签页
},
"content_scripts":[{ // 指定向web页面注入的脚本/css。
"matches":[], // 匹配的url
"css":[], // 注入的css资源路径
"js":[], // 注入的js资源路径
"run_at":"" // 注入的时机。 document_start|end|idle
"all_frames":1, // 是否运行在所有frame中
...
}],
"content_security_policy": "", // 安全策略
"homepage_url": "http://xxx", // 扩展的官方主页
"options_page": "", // 选项页。用于在扩展管理页面跳转到选项设置
"permissions":[ // 权限
"bookmarks", // 启用书签权限
"contextMenus", // 启用右键菜单权限
"cookies", // 启用cookie权限
"experimental", // 启用chrome的实验性功能API
"history", // 启用history权限
"notifications", // 启用桌面通知权限
"tabs", // 启用标签权限
"activeTab", // 启用活动标签权限
...
],
"requirements": {}, // 指定所需要的特殊技术。目前只支持"3D"
"update_url": "", // 自动升级
"plugins":[], // 扩展。 可调用第三方扩展
"web_accessible_resources": [] // 指定资源路径,为String数组
...
}
复制代码
2、如何优雅处理前后通信
问题:传统处理通信,当请求众多,background.js 中监听的请求处理逻辑大,手动引入注册监听费事。
// CS页面发起请求
chrome.extension.sendRequest({
...
},function(res){
})
// background.js监听请求
chrome.extension.onRequest.addListener(
function(request,sender,sendResponse){
switch(...){
case ...: // 通过request匹配出请求标识
...; // 引入或编写对应的业务逻辑
break;
}
}
)
复制代码
解决方案:工程化,通过 webpack 的能力,自动注册监听
设计目录结构
requestModule/
index.js // 获取所有的请求监听模块
requestModule1.js // 请求监听模块
requestModule2.js
regesiterRequest.js // 注册监听
复制代码
代码实现
// requestModule/index.js
// 注册所有的导出的请求监听函数
let requestProvider = {}
//获取一系列完整的依赖关系 参数解释:(目录,是否包含子目录,匹配文件)
const request = require.context('./', false, /^((?!index).)*\.js$/)
request.keys().forEach(path => {
const module = request(path).default || request(path)
Object.keys(module).forEach(key => {
if (module[key] && requestProvider[key]) {
throw new Error(`${key}该函数名已被占用,请更换函数名`)
}
requestProvider[key] = module[key]
})
})
export default requestProvider
复制代码
// regesiterRequest.js
import isFunction from 'lodash/isFunction'
import requestProvider from './requestModule/index'
// 注册所有的请求监听
chrome.extension.onRequest.addListener(
function(request, sender, sendResponse) {
if (!request.name) {
throw 'request的name值,是必传参数!'
}
if (filterFn.indexOf(request.name) > -1) {
return
}
if (!isFunction(requestProvider[request.name])) {
console.warn(`requestProvider中不存在 ${request.name} 这个方法!`)
return
}
if(typeof requestProvider[request.name] === 'function'){
requestProvider[request.name](request, sendResponse)
}
}
);
复制代码
3、拦截 HTTP 请求
a、声明权限(manifest.json)
{
"permissions":{
"webRequest"
}
}
复制代码
b、介绍 onBeforeSendHeaders 的使用:允许添加/修改/删除 request headers
// 例子:删除所有的request中User-Agent的Header
chrome.webRequest.onBeforeSendHeaders.addListener(
function(details) {
for (var i = 0; i < details.requestHeaders.length; ++i) {
if (details.requestHeaders[i].name === 'User-Agent') {
details.requestHeaders.splice(i, 1);
break;
}
}
return {requestHeaders: details.requestHeaders};
},
{urls: ["<all_urls>"]},
["blocking", "requestHeaders"]
);
复制代码
c、介绍 onBeforeRequest 的使用:在 TCP 连接建立之后和 HTTP 数据发送之前被调用的事件
// 例子:阻止发往百度的request
chrome.webRequest.onBeforeRequest.addListener(
function(details) {
return {cancel: details.url.indexOf("://www.baidu.com/") != -1};
},
{urls: ["<all_urls>"]},
["blocking"]
);
复制代码
d、API 文档
// onBeforeSendHeaders的callback的参数details结构
details = {
tabId: integer, //如果没有和tab关联则返回-1
parentFrameId: integer,
url: string,
timeStamp: double,
//0表示request是在main frame里发生的
frameId: integer,
requestId: string,
requestHeaders: HttpHeaders, // optional
type: enumerated_string, //value in: ["main_frame", "sub_frame", "stylesheet", "script", "image", "object", "xmlhttprequest", "other"]
method: string //标准HTTP方法
};
RequestFilter = {
tabId: interger, //optional
//URL的数组,或者是匹配URL的pattern
urls: array_of_string,
//可选的值有:"main_frame", "sub_frame", "stylesheet", "script", "image", "object", "xmlhttprequest", "other"
types: array_of_enumerated_string, //optional
windowId: integer //optional
};
// 设置了blocking关键字的就用这个object来作为block的规则了
BolockingResponse = {
//为true的话request被cancel,在onBeforeRequest里面用哦
cancel: boolean, //optional
//只在onBeforeRequest事件中使用,用来掉包的关键属性!!!
redirectUrl: string, //option
//只用在onHeadersReceived事件里,在浏览器返给server时把header给掉包
responseHeaders: HttpHeaders //optional
//只在onBeforeSendHeaders事件中使用。是另一个用来掉包的关键属性!!!
requestHeaders: HttpHeaders //optional
//只在onAuthRequred事件中使用,当然也是用来掉包的
authCredentials: object //optional
};
复制代码
4、 域绝缘下,操作 PageScript 页的 JS 对象
往页面注册脚本,操作对象。常用于对编辑器的功能增强需求。
const originInject = function(jsPath, id, cb) {
if(id && document.getElementById(id)){
typeof cb==="function" && cb()
return;
}
jsPath = jsPath || ''
var temp = document.createElement('script')
temp.setAttribute('type', 'text/javascript')
// 获得的地址类似:chrome-extension://****/js/inject.js
temp.src = chrome.extension.getURL(jsPath)
if(id){
temp.id = id
}
temp.onload = function()
{
typeof cb=="function" && cb()
};
document.head.appendChild(temp)
}
复制代码
5、开发支持热更新
webpack-chrome-extension-reloader:扩展程序热更新插件
// webpack.config.js
{
...
plugins:initPlugins.concat([new ChromeReloadPlugin({
port: config.port,
reloadPage: true,
entries: {
// 背景页
background: 'background',
// 配置ContentScripts的路径
contentScript: Object.keys(entries).filter(function (item) {
return item.indexOf('content-scripts') > -1
})
}
})])
}
复制代码
--END--
作者:梁龙先森 WX:newBlob
原创作品,抄袭必究!
划线
评论
复制
发布于: 2020 年 11 月 15 日阅读数: 90
版权声明: 本文为 InfoQ 作者【梁龙先森】的原创文章。
原文链接:【http://xie.infoq.cn/article/77b074f7b1a5db27b86ea960f】。文章转载请联系作者。
梁龙先森
关注
脚踏V8引擎的无情写作机器 2018.03.17 加入
还未添加个人简介
评论