MV3扩展Service Worker中Axios报adapter is not a function错误
问题产生原因
Manifest V3 规范下扩展的后台运行在 Service Worker 上下文,这个环境既不存在浏览器环境的XMLHttpRequest对象,也不存在 Node.js 环境的http/https内置模块。
Axios 默认自带两个请求适配器:
- 浏览器端用的
xhr适配器,依赖XMLHttpRequest实现 - Node.js 端用的
http适配器,依赖 Node 原生http模块
Axios 初始化时会自动检测当前运行环境选择可用适配器,在 Service Worker 环境下两个默认适配器都无法运行,自动检测匹配失败,就会抛出TypeError: adapter is not a function错误。
现有配置还存在两个隐含问题:
- 代码中使用了
storage.local读写配置,但manifest.json的permissions里没有声明storage权限,后续读写缓存会报错 - Manifest V3 中后台脚本发起跨域请求需要声明
host_permissions,当前配置没有加对应权限,适配器修复后请求也会被浏览器拦截。
把请求从 content script 转发到后台的思路是正确的:content script 运行在目标页面的上下文,受页面同源策略限制才会触发 CORS 错误,后台 Service Worker 属于扩展独立上下文,本身不受站点 CORS 规则限制,只要声明对应 host 权限就可以正常发起跨域请求。
修复步骤
1. 补全manifest必要权限
修改manifest.json,补全缺失的权限配置:
{ "manifest_version": 3, "name": "Teamlock web extension", "description": "Teamlock web extension", "version": "0.0.1", "background": { "service_worker": "/background.js" }, "action": { "default_popup": "popup.html" }, "content_scripts": [ { "matches": [ "<all_urls>" ], "js": [ "/content.js" ] } ], "permissions": [ "tabs", "storage" ], "host_permissions": [ "<all_urls>" // 遵循最小权限原则的话,可以替换为实际接口域名,例如 "https://api.your-teamlock-domain.com/*" ] }
2. 给Axios显式指定Service Worker可用的适配器
Service Worker 原生支持fetch API,安装对应的fetch适配器给Axios使用即可:
- 首先安装依赖包:
npm install @vespaiach/axios-fetch-adapter
- 修改封装的http模块,创建实例时显式指定适配器:
import axios from "axios" import fetchAdapter from "@vespaiach/axios-fetch-adapter" import { storage } from "webextension-polyfill"; const service = axios.create({ adapter: fetchAdapter }) // 原有请求拦截器逻辑保持不变 service.interceptors.request.use( async (config) => { const {token} = await storage.local.get("token") if (token) { config.headers["Authorization"] = `Bearer ${token}` } const {instance} = await storage.local.get("instance") config.baseURL = instance; return config }, (error) => { console.log(error) return Promise.reject(error) } ) export default service
3. 修正后台消息监听逻辑
首先补全http模块的导入,另外注意扩展消息传递只能序列化普通对象,Axios返回的响应实例包含大量不可序列化的属性,需要手动提取有效字段再返回,避免消息传递报错:
import {runtime} from "webextension-polyfill"; import http from "./path/to/your/http-module"; // 替换成http模块的实际路径 runtime.onMessage.addListener(async (request,sender) =>{ console.log("bien reçu"); const res = await http.get(`/api/v1/workspace`) // 仅返回可序列化的必要字段 return { data: res.data, status: res.status, headers: res.headers } })
如果不想额外引入适配器依赖,也可以直接在后台Service Worker中用原生fetch封装请求逻辑,不需要依赖Axios,适合请求逻辑简单的场景。
内容的提问来源于stack exchange,提问作者patacoing
相关产品推荐
相关产品推荐

