Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chrome 请求过滤扩展实现 #86

Open
XXHolic opened this issue May 3, 2021 · 0 comments
Open

Chrome 请求过滤扩展实现 #86

XXHolic opened this issue May 3, 2021 · 0 comments

Comments

@XXHolic
Copy link
Owner

XXHolic commented May 3, 2021

目录

引子

接着 Chrome 扩展 : 入门,接下来实现一开始自己的想法:网络请求过滤。简单的说就是监听某个网站的所有请求,把想要的请求在扩展插件中展示出来。扩展名为 Capture Request 。

需求具体化

上面的想法比较模糊,为了达到这个目的,结合文档的示例,要做的有:

  1. 扩展要有对应的图标及提示。
  2. 点击工具栏扩展图标,打开一个新的 Tab 页面,用来展示请求的相关信息。
  3. 扩展监听处于激活 Tab 的网站请求,可以配置过滤监听的网址。
  4. 对监听的请求,支持根据 url 筛选并导出。

有些功能不方便直接在文档找到,这个时候,建议在 Chrome 商店找一个开源扩展,根据效果看里面用的一些 API ,然后找到对应文档。这里参考了 FeHelper 里面的一些实现。需要注意到是 FeHelper 开发基于 manifest_version 版本为 2 ,以下开发扩展基于的版本是推荐的版本为 3 ,完整代码见 Capture Request

实现

图标相关信息配置

按照入门里面介绍的信息,图标可能出现的地方有工具栏、扩展管理页、权限警告和 favicon 上,在 manifest.json 中配置的下面相关字段:

{
  "name": "Capture Request",
  "description": "Capture Request",
  "version": "1.0",
  "manifest_version": 3,
  "action": {
    "default_icon": {
      "16": "xxx.png",
      "32": "xxx.png",
    }
  },
  "icons":{
    "16": "xxx.png",
    "32": "xxx.png",
  }
}

什么尺寸图标用在什么地方的详细说明在这里,文档上推荐用 PNG 的图片格式。按照这个来,发现有的图标太小了会看起来明显模糊,也可以用比较大的尺寸,Chrome 会自己把图片压缩到需要的尺寸。

点击扩展打开新 Tab 页面

入门里面点击扩展的展现形式是打开了一个弹窗,在文档 Design the user interface 中介绍的形式有 Popup 、Tooltip、Omnibox、Context menu、Override pages ,最有可能就是 Override pages ,但试了一下发现没有效果,于是去看别人的实现,发现可以通过监听点击图标事件打开新 Tab 。

但看似可以直接用的 API ,实际上还有下面几点要考虑:

  1. 在哪里监听这事件?
  2. 什么时候监听这个事件?
  3. 怎么打开新 Tab ?
  4. 是否需要权限,如果需要,涉及那些权限?

入门里面添加功能是通过后台脚本,文档开头说的一句个人觉得很重要:

扩展是通过基于事件编程来改变或增强 Chrome 浏览体验。

从文档中可以发现,在后台脚本中可以解决上面提的第 1、2 两个问题,需要的权限是 scripting

打开 Tab 使用的 API 是 chrome.tabs ,需要的权限是 tabs

主要做法是在 manifest.json 中添加下面配置:

{
  ...
+ "permissions": [
+   "scripting",
+   "tabs",
+ ],
+ "background": {
+   "service_worker": "background.js"
+ },
  ...
}

然后新建后台脚本文件 background.js ,并添加下面主要逻辑代码:

chrome.action.onClicked.addListener(() => {
  chrome.tabs.create({
    url: 'page.html'
  });
});

监听请求及配置

要把处于激活 Tab 网站上的请求显示到打开的扩展页面上,主要需要考虑的点有:

  1. 怎么找到激活的 Tab ?
  2. 怎么截获网页请求?
  3. 截获的请求怎么同步到扩展自定义页面上?

通过上面打开 Tab 的效果实现,可以联想到相关的 API 应该也在 chrome.tabs 中,发现提供了 query 方法可以解决第 1 个问题。

截获请求的方法通过网上搜索,发现文档 chrome.webRequest ,里面详细的介绍了扩展中请求的生命周期及触发的事件,经过对比思考,个人最后决定监听 onResponseStarted 事件,需要的权限是 webRequest 。这样就解决了第 2 个问题。

参照入门里面改变颜色的方式,类似的可以把请求缓存到 chrome.storage ,然后在扩展页面获取,需要的权限是 storage 。关于数据同步,可以通过监听 chrome.storage.onChanged 事件拿到变动的最新数据。这样就解决了第 3 个问题。

在调试的过程中,发现存在本地的数据使用 chrome.storage.sync 时,请求达到一定量后,会报错。看了文档发现这种方式的最大值有一定的限制,不太适合存储大量请求数据的场景,使用 chrome.storage.local 更加合适。

配置过滤请求的方式可直接按照入门里面的配置方式处理,但有一点需要注意的是,每当配置更新的时候,需要重新监听 onResponseStarted 事件。

主要做法是在 manifest.jsonpermissions 字段中添加 webRequeststorage

background.js 中添加主要代码:

// 储存请求数据默认值
let requestList = []
// 网址过滤的默认值
let urlPattern = '<all_urls>'

// 监听请求事件的处理程序
const handlerResponseStarted = (details) => {
  // 找到处于激活状态的 Tab
  chrome.tabs.query({ active: true }, (tab) => {
    requestList.unshift(details)
    chrome.storage.local.set({ requestList });
    return { cancel: true };
  })
}

// 监听 storage 改变事件
chrome.storage.onChanged.addListener((changeObj, areaName) => {
  const { urlPattern } = changeObj
  // 由于在 page.html 里面也监听了,所以要判断是不是 urlPattern 变动了
  if (areaName !== 'local' || !urlPattern) {
    console.warn('urlPattern does not change')
    return;
  }
  const { newValue } = urlPattern
  const hasAddListen = chrome.webRequest.onResponseStarted.hasListener(handlerResponseStarted)
  if (hasAddListen) {
    chrome.webRequest.onResponseStarted.removeListener(handlerResponseStarted);
  }
  chrome.webRequest.onResponseStarted.addListener(
    handlerResponseStarted,
    { urls: [newValue] },
  );
})

为扩展页面 page.html 添加脚本文件 pages.js ,添加关键逻辑:

  chrome.storage.onChanged.addListener((changeObj, areaName) => {
    const { requestList } = changeObj
    // 由于在 background.js 里面也监听了,所以要判断是不是 requestList 变动了
    if (areaName !== 'local' || !requestList) {
      console.warn('requestList does not change')
      return;
    }
    const { newValue } = requestList || { newValue: [] }
    const newItem = newValue[0] || null
    if (!newItem) {
      console.warn('no data')
      return;
    }
    // 显示数据的逻辑
    showData(newItem)
  })

导出数据

截获了想要的数据,有需要导出到本地使用的场景,参考 FeHelper 里面的实现,找到了文档 chrome.downloads ,需要的权限是 downloads

主要做法是在 manifest.jsonpermissions 字段中添加 downloads

pages.js 添加关键逻辑:

  let localFilterList = []; // 页面筛选后的数据
  // 点击导出的按钮
  const exportEle = document.querySelector('#operate-export')
  exportEle.addEventListener('click', () => {
    if (!localFilterList.length) {
      alert('无有效数据')
      return;
    }
    const txt = JSON.stringify(localFilterList)
    let blob = new Blob([txt], { type: 'application/octet-stream' });
    // 文件名称获取时间的秒数,可按照自己喜好定义
    let dt = (new Date()).getSeconds();
    chrome.downloads.download({
      url: URL.createObjectURL(blob),
      saveAs: true,
      conflictAction: 'overwrite',
      filename: dt + '.json'
    });
  })

参考资料

🗑️

最近看了下电视剧《围城》,虽然年代很早,但真是有趣,据说是完全按照原著拍的,没有任何改编。

在小说的最后一段才讲的是婚姻围城,不知道什么时候开始起,我一直以为整本书讲的是关于结婚的围城。

83-poster

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant