npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

ext-xhr-interceptor

v1.1.7

Published

一个强大的 XMLHttpRequest 拦截器,支持请求和响应的拦截、修改和监听

Readme

XHR Interceptor

一个强大的 XMLHttpRequest 拦截器,支持请求和响应的拦截、修改和监听。使用 Proxy 技术实现,无需修改现有代码即可拦截所有 XHR 请求。

特性

  • 🚀 零侵入性: 使用 Proxy 技术,无需修改现有代码
  • 🎯 精确匹配: 支持字符串、正则表达式和数组匹配目标 URL
  • 🔧 灵活配置: 支持请求前修改、响应后处理、错误处理等
  • 📊 完整信息: 提供请求和响应的完整信息,包括 headers、query 参数等
  • 🛡️ 类型安全: 完整的 TypeScript 类型定义
  • 📦 轻量级: 无外部依赖,体积小巧

安装

NPM 安装

npm install ext-xhr-interceptor

或者使用 yarn:

yarn add ext-xhr-interceptor

CDN 引入

你也可以通过 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 修改后的数据

beforeRequestbeforeResponse 中修改数据后,必须 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

beforeRequestbeforeResponse 都支持异步函数,可以使用 async/await

interceptXHR({
  targetUrl: '/api',
  beforeResponse: async (responseConfig) => {
    // ✅ 会等待异步操作完成
    await new Promise(resolve => setTimeout(resolve, 1000));
    responseConfig.response.delayed = true;
    return responseConfig;
  }
});

回调执行顺序

完整的执行顺序如下:

  1. beforeRequest - 修改请求
  2. onRequest - 监听请求(看到修改后的数据)
  3. 发送网络请求
  4. beforeResponse - 修改响应
  5. onResponse - 监听响应(看到修改后的数据)
  6. XHR 的 onload 回调(收到修改后的数据)

注意事项

  1. 浏览器兼容性: 需要支持 Proxy 的现代浏览器
  2. 性能影响: 拦截器会对所有匹配的请求产生影响,建议合理设置匹配规则
  3. 内存泄漏: 长时间运行时注意清理不需要的监听器
  4. 调试模式: 生产环境建议关闭详细的日志输出
  5. return 语句: beforeRequestbeforeResponse 必须返回修改后的配置对象

开发

# 安装依赖
npm install

# 开发模式
npm run dev

# 构建
npm run build

# 清理构建文件
npm run clean

许可证

MIT License

贡献

欢迎提交 Issue 和 Pull Request!

更新日志

v1.2.0

  • 重大改进: beforeRequestbeforeResponse 现在支持 async/await
  • 🐛 Bug 修复: 修复 beforeResponse 序列化整个 responseConfig 而非 response 字段的问题
  • 🐛 Bug 修复: 修复 onResponseonRequest 收不到修改后数据的问题
  • 新增: 现在同时更新 responseresponseText 属性,确保兼容性
  • 📚 文档: 添加详细的使用示例和注意事项
  • 🧪 测试: 添加完整的功能测试文件

v1.1.0

  • 🎉 新增 UMD 格式支持,现在可以通过 script 标签直接在浏览器中使用
  • 📦 添加 CDN 引入方式
  • 📚 更新文档,添加 script 标签使用示例

v1.0.0

  • 初始版本发布
  • 支持基本的 XHR 拦截功能
  • 提供完整的 TypeScript 类型定义