当前位置: 首页 > news >正文

Chrome V3 插件开发:监听并转发 API 请求

基于 Manifest V3 实现 Chrome 插件的网络请求监听与转发

本指南详细说明如何从零开始创建一个 API 监控与转发的 Chrome 扩展插件


📋 目录

  1. 项目概述
  2. 核心架构
  3. Manifest V3 配置
  4. 核心代码实现
  5. 国际化配置
  6. 完整工作流程
  7. 调试技巧

项目概述

功能目标

创建一个 Chrome 扩展,能够:

  • ✅ 拦截网页的 fetch()XMLHttpRequest API 请求
  • ✅ 捕获完整的请求/响应数据(headers、body、status 等)
  • ✅ 将捕获的数据转发到自定义 Webhook 端点
  • ✅ 支持多语言(中文/英文)
  • ✅ 提供可视化配置界面

技术栈

  • Manifest V3 - Chrome 扩展最新规范
  • Content Scripts - 注入脚本到网页
  • Service Worker - 后台处理
  • Chrome Storage API - 配置存储
  • Chrome i18n API - 国际化

核心架构

三层通信架构

┌──────────────────────────┐
│   目标网页 (MAIN world)   │
│  - 拦截 fetch/XHR         │
│  - 捕获请求/响应           │
└─────────┬────────────────┘│ postMessage▼
┌──────────────────────────┐
│  Bridge (ISOLATED world)  │
│  - 接收 MAIN 数据         │
│  - 转发到 Service Worker  │
└─────────┬────────────────┘│ chrome.runtime.sendMessage▼
┌──────────────────────────┐
│   Service Worker 后台     │
│  - 管理配置               │
│  - 转发到 Webhook         │
└──────────────────────────┘

为什么需要三层架构?

Manifest V3 的安全限制:

  1. MAIN world - 可以访问网页的原生 API(fetch、XHR),但无法访问 Chrome API
  2. ISOLATED world - 可以访问 Chrome API,但无法访问网页的原生对象
  3. Service Worker - 处理后台任务,无法直接访问网页

解决方案: 使用 postMessage 桥接 MAIN 和 ISOLATED world


Manifest V3 配置

1. 基础配置 manifest.json

{"manifest_version": 3,"name": "__MSG_extName__","description": "__MSG_extDescription__","default_locale": "en","version": "2.0.0","icons": {"16": "logo/logo-16.png","48": "logo/logo-48.png","128": "logo/logo-128.png"},"permissions": ["storage",    // 存储配置"tabs"        // 获取当前标签页信息],"host_permissions": ["<all_urls>"  // 访问所有网站(监控用)],"background": {"service_worker": "service-worker.js"},"content_scripts": [{"js": ["content-main.js"],"matches": ["<all_urls>"],"run_at": "document_start","all_frames": false,"world": "MAIN"           // 🔑 关键:运行在 MAIN world},{"js": ["content-bridge.js"],"matches": ["<all_urls>"],"run_at": "document_start","all_frames": false        // 默认 ISOLATED world}],"action": {"default_title": "API Mirror","default_popup": "popup/popup.html"},"options_page": "config/config.html"
}

关键配置说明

字段 说明 重要性
manifest_version: 3 使用 V3 规范 ⭐⭐⭐
world: "MAIN" 运行在网页主环境,可拦截原生 API ⭐⭐⭐
run_at: "document_start" 页面加载前注入,确保拦截所有请求 ⭐⭐⭐
all_frames: false 只在主框架运行,避免重复 ⭐⭐
host_permissions V3 中独立于 permissions ⭐⭐⭐

核心代码实现

1. Content Script (MAIN World) - 拦截 API

文件:content-main.js

(function () {'use strict';// 防止重复注入if (window.__API_MONITOR_INJECTED__) return;window.__API_MONITOR_INJECTED__ = true;const currentDomain = window.location.hostname;let siteConfig = null;let isConfigured = false;// 📨 监听来自 Bridge 的配置window.addEventListener('message', function (event) {if (event.source !== window) return;if (event.data?.type === 'API_MONITOR_CONFIG') {siteConfig = event.data.config;isConfigured = true;}});// 📤 请求配置window.postMessage({type: 'API_MONITOR_REQUEST_CONFIG',domain: currentDomain}, '*');// ✅ 判断是否需要监控此 URLfunction shouldMonitorURL(url) {if (!isConfigured || !siteConfig?.enabled) return false;return siteConfig.apis.some(api => {if (!api.enabled) return false;switch (api.matchType) {case 'exact':return url === api.pattern;case 'contains':return url.includes(api.pattern);case 'startsWith':return url.startsWith(api.pattern);case 'regex':try {return new RegExp(api.pattern).test(url);} catch (e) {return false;}default:return url.includes(api.pattern);}});}// 📤 发送数据到 Bridgefunction sendToBackground(data) {window.postMessage({type: 'API_MONITOR_TO_BRIDGE',payload: data}, '*');}// 🎣 Hook Fetch APIconst originalFetch = window.fetch;window.fetch = function (...args) {const url = typeof args[0] === 'string' ? args[0] : args[0]?.url;// 捕获请求体let requestBody = null;if (args[1]?.body) {try {requestBody = typeof args[1].body === 'string' ? JSON.parse(args[1].body) : args[1].body;} catch (e) {requestBody = args[1].body;}}const fetchPromise = originalFetch.apply(this, args);// 异步捕获响应fetchPromise.then(async response => {if (shouldMonitorURL(url)) {const clonedResponse = response.clone();try {const responseBody = await clonedResponse.json().catch(() => null);const capturedData = {domain: currentDomain,url: url,method: args[1]?.method || 'GET',timestamp: new Date().toISOString(),status: response.status,statusText: response.statusText,requestHeaders: args[1]?.headers || {},requestBody: requestBody,responseBody: responseBody};sendToBackground({type: 'API_CAPTURED',data: capturedData
http://www.dtcms.com/a/600717.html

相关文章:

  • OpenCV 图像处理与键盘交互
  • 长沙理工《人工智能基础A》实验(上机)报告实验三 电商数据可视化/图像处理
  • Elasticsearch 的结构化文档配置 - 递归分块实践
  • 如何在IIS中配置HTTP重定向
  • elasticsearch 安装 repository-oss 插件
  • 宝安做网站哪家好德阳网站建设熊掌号
  • 输入10个整数存放于数组中,并将最小的数与数组的第一个元素交换,最大的数与数组的最后一个元素交换
  • 从 WAL 到 Fluss->Flink CDC Postgres Connector 端到端同步实战
  • 数据结构 图 的邻接表建立
  • C++CUDA实战:通过两个图像算法,搞懂了GPU编程
  • RabbitMQ应用(2)
  • Spring Boot 中的消息队列集成:从 RabbitMQ 到 Kafka 的深度实践
  • Spring Boot 与 RabbitMQ 集成示例
  • 家纺 网站模版想自己做网站流程
  • 将 CentOS 风格的命令行提示符(如 [root@slave1 ~]#)修改为 Ubuntu 风格
  • k8s各种场景下排错思路以及命令 k8s常见问题故障处理思路
  • win32k源代码分析之win32k!IsSAS函数中的全局变量win32k!gfsSASModifiers = 3是什么时候被赋值的
  • 序列和可迭代
  • 16.udp_socket(二)
  • 如何在不使用iTunes的情况下在电脑上访问iPhone文件
  • python+websockets,报错RuntimeError: no running event loop
  • 自己做网站流程龙口市最新公告
  • 自助建站系统介绍wordpress 百度推广
  • 基于Springboot的汽车推荐系统设计与实现7f7h74np(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
  • DBLoss: Decomposition-based Loss Function for Time Series Forecasting 论文阅读
  • STM32F103学习笔记-16-RCC(第4节)-使用 HSI 配置系统时钟并用 MCO 监控系统时钟
  • Git 中新建学习分支 + 暂存修改 + VSCode 可视化查看改动(超详细教程)
  • Linux高效编程与实战:自动化构建工具“make/Makefile”和第一个系统程序——进度条
  • Docker 相关使用收录
  • 【详细步骤解析】爬虫小练习——爬取豆瓣Top250电影,最后以csv文件保存,附源码