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.jsregesiterRequest.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的Headerchrome.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 数据发送之前被调用的事件
// 例子:阻止发往百度的requestchrome.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 加入
还未添加个人简介











评论