ext-xhr-interceptor
v1.1.7
Published
一个强大的 XMLHttpRequest 拦截器,支持请求和响应的拦截、修改和监听
Maintainers
Readme
XHR Interceptor
一个强大的 XMLHttpRequest 拦截器,支持请求和响应的拦截、修改和监听。使用 Proxy 技术实现,无需修改现有代码即可拦截所有 XHR 请求。
特性
- 🚀 零侵入性: 使用 Proxy 技术,无需修改现有代码
- 🎯 精确匹配: 支持字符串、正则表达式和数组匹配目标 URL
- 🔧 灵活配置: 支持请求前修改、响应后处理、错误处理等
- 📊 完整信息: 提供请求和响应的完整信息,包括 headers、query 参数等
- 🛡️ 类型安全: 完整的 TypeScript 类型定义
- 📦 轻量级: 无外部依赖,体积小巧
安装
NPM 安装
npm install ext-xhr-interceptor或者使用 yarn:
yarn add ext-xhr-interceptorCDN 引入
你也可以通过 script 标签直接在浏览器中使用:
<script src="https://unpkg.com/ext-xhr-interceptor@latest/dist/index.browser.js"></script>或者下载到本地使用:
<script src="./path/to/index.browser.js"></script>使用方法
ES 模块方式
import { interceptXHR } from 'ext-xhr-interceptor';
// 拦截所有包含 '/api' 的请求
interceptXHR({
targetUrl: '/api',
onRequest: (config) => {
console.log('拦截到请求:', config);
},
onResponse: (response) => {
console.log('拦截到响应:', response);
}
});Script 标签方式
<script src="https://unpkg.com/ext-xhr-interceptor@latest/dist/index.browser.js"></script>
<script>
// 通过全局变量 XHRInterceptor 访问
XHRInterceptor.interceptXHR({
targetUrl: '/api',
onRequest: (config) => {
console.log('拦截到请求:', config);
},
onResponse: (response) => {
console.log('拦截到响应:', response);
}
});
// 或者使用解构赋值
const { interceptXHR } = XHRInterceptor;
interceptXHR({
targetUrl: '/api',
onRequest: (config) => {
console.log('拦截到请求:', config);
}
});
</script>高级配置
import { interceptXHR } from 'ext-xhr-interceptor';
interceptXHR({
// 支持多种匹配方式
targetUrl: ['/api', /\.json$/, 'https://example.com'],
// 请求前处理(支持 async)
beforeRequest: async (config) => {
// 可以执行异步操作
const token = await getAuthToken();
// 修改请求头
config.headers['Authorization'] = `Bearer ${token}`;
config.headers['X-Custom-Header'] = 'value';
// 修改请求体
if (config.body) {
config.body.extraField = 'extra value';
}
// ⚠️ 必须 return,否则修改不生效
return config;
},
// 响应后处理(支持 async)
beforeResponse: async (responseConfig) => {
// 可以执行异步操作(如数据转换、缓存等)
await saveToCache(responseConfig.response);
// 修改响应数据
if (responseConfig.status === 200) {
responseConfig.response.extraField = 'response value';
responseConfig.response.timestamp = Date.now();
}
// ⚠️ 必须 return,否则修改不生效
return responseConfig;
},
// 请求监听(在 beforeRequest 之后调用,可以看到修改后的数据)
onRequest: (config) => {
console.log('请求配置:', {
method: config.method,
url: config.url,
headers: config.headers,
body: config.body,
query: config.query
});
},
// 响应监听(在 beforeResponse 之后调用,可以看到修改后的数据)
onResponse: (responseConfig) => {
console.log('响应数据:', {
status: responseConfig.status,
headers: responseConfig.headers,
response: responseConfig.response,
matchedPattern: responseConfig.matchedPattern
});
},
// 错误处理
onError: (error, phase) => {
console.error(`${phase}阶段发生错误:`, error);
}
});API 文档
interceptXHR(options: XHRInterceptorOptions)
参数
options.targetUrl:string | RegExp | Array<string | RegExp>- 目标 URL 匹配模式options.beforeRequest?:(config: RequestConfig) => RequestConfig | Promise<RequestConfig>- 请求前处理函数options.beforeResponse?:(response: ResponseConfig) => ResponseConfig | Promise<ResponseConfig>- 响应后处理函数options.onRequest?:(config: RequestConfig) => void- 请求监听函数options.onResponse?:(response: ResponseConfig) => void- 响应监听函数options.onError?:(error: Error, phase: 'request' | 'response') => void- 错误处理函数
类型定义
interface RequestConfig {
method: any;
url: string;
query?: Record<string, string>;
headers: Record<string, string>;
body: any;
withCredentials?: boolean;
}
interface ResponseConfig<T = any> {
status: number;
headers: Record<string, string>;
response: T;
matchedPattern: string | RegExp;
requestConfig: RequestConfig;
}使用场景
1. API 调试
interceptXHR({
targetUrl: '/api',
onRequest: (config) => {
console.log('API 请求:', config);
},
onResponse: (response) => {
console.log('API 响应:', response);
}
});2. 请求修改
interceptXHR({
targetUrl: '/api/auth',
beforeRequest: (config) => {
// 自动添加认证头
config.headers['Authorization'] = `Bearer ${getToken()}`;
return config; // ⚠️ 必须 return
}
});3. 响应数据处理(修改响应)
interceptXHR({
targetUrl: '/api/user',
beforeResponse: (responseConfig) => {
// 修改响应数据
responseConfig.response.modified = true;
responseConfig.response.timestamp = Date.now();
// ⚠️ 必须 return,否则修改不生效
return responseConfig;
}
});
// 发送请求
const xhr = new XMLHttpRequest();
xhr.open('GET', '/api/user');
xhr.onload = function() {
const data = JSON.parse(xhr.response);
console.log(data.modified); // true
console.log(data.timestamp); // 时间戳
};
xhr.send();4. Mock 数据(完全替换响应)
interceptXHR({
targetUrl: '/api/data',
beforeResponse: (responseConfig) => {
// 完全替换响应数据,实现 Mock
responseConfig.response = {
code: 0,
message: 'success',
data: {
id: 1,
name: '模拟数据',
items: [1, 2, 3, 4, 5]
}
};
return responseConfig;
}
});5. 异步数据处理
interceptXHR({
targetUrl: '/api',
beforeResponse: async (responseConfig) => {
// 执行异步操作(如从 IndexedDB 读取、API 调用等)
const cachedData = await getCachedData(responseConfig.requestConfig.url);
// 合并缓存数据和响应数据
responseConfig.response.cached = cachedData;
// 保存到缓存
await saveToCache(responseConfig.response);
return responseConfig;
}
});6. 条件修改
interceptXHR({
targetUrl: '/api',
beforeResponse: (responseConfig) => {
// 根据请求方法决定是否修改
if (responseConfig.requestConfig.method === 'POST') {
responseConfig.response.postProcessed = true;
}
// 根据响应状态修改
if (responseConfig.status === 404) {
responseConfig.response = {
error: 'Not Found',
fallbackData: []
};
}
return responseConfig;
}
});7. 错误监控
interceptXHR({
targetUrl: ['/api', '/v1'],
onError: (error, phase) => {
// 上报错误到监控系统
reportError({
type: 'xhr_error',
phase,
error: error.message,
timestamp: Date.now()
});
}
});重要提示 ⚠️
必须 return 修改后的数据
在 beforeRequest 和 beforeResponse 中修改数据后,必须 return,否则修改不会生效:
// ✅ 正确用法
interceptXHR({
targetUrl: '/api',
beforeResponse: (responseConfig) => {
responseConfig.response.modified = true;
return responseConfig; // ✅ 必须 return
}
});
// ❌ 错误用法
interceptXHR({
targetUrl: '/api',
beforeResponse: (responseConfig) => {
responseConfig.response.modified = true;
// ❌ 没有 return,修改不会生效!
}
});支持 async/await
beforeRequest 和 beforeResponse 都支持异步函数,可以使用 async/await:
interceptXHR({
targetUrl: '/api',
beforeResponse: async (responseConfig) => {
// ✅ 会等待异步操作完成
await new Promise(resolve => setTimeout(resolve, 1000));
responseConfig.response.delayed = true;
return responseConfig;
}
});回调执行顺序
完整的执行顺序如下:
beforeRequest- 修改请求onRequest- 监听请求(看到修改后的数据)- 发送网络请求
beforeResponse- 修改响应onResponse- 监听响应(看到修改后的数据)- XHR 的
onload回调(收到修改后的数据)
注意事项
- 浏览器兼容性: 需要支持 Proxy 的现代浏览器
- 性能影响: 拦截器会对所有匹配的请求产生影响,建议合理设置匹配规则
- 内存泄漏: 长时间运行时注意清理不需要的监听器
- 调试模式: 生产环境建议关闭详细的日志输出
- return 语句:
beforeRequest和beforeResponse必须返回修改后的配置对象
开发
# 安装依赖
npm install
# 开发模式
npm run dev
# 构建
npm run build
# 清理构建文件
npm run clean许可证
MIT License
贡献
欢迎提交 Issue 和 Pull Request!
更新日志
v1.2.0
- ✨ 重大改进:
beforeRequest和beforeResponse现在支持 async/await - 🐛 Bug 修复: 修复
beforeResponse序列化整个responseConfig而非response字段的问题 - 🐛 Bug 修复: 修复
onResponse和onRequest收不到修改后数据的问题 - ✨ 新增: 现在同时更新
response和responseText属性,确保兼容性 - 📚 文档: 添加详细的使用示例和注意事项
- 🧪 测试: 添加完整的功能测试文件
v1.1.0
- 🎉 新增 UMD 格式支持,现在可以通过 script 标签直接在浏览器中使用
- 📦 添加 CDN 引入方式
- 📚 更新文档,添加 script 标签使用示例
v1.0.0
- 初始版本发布
- 支持基本的 XHR 拦截功能
- 提供完整的 TypeScript 类型定义
