1. 为什么我们需要 AJAX 请求拦截在现代前端开发中拦截 AJAX 请求已经成为一项必备技能。想象一下这样的场景你正在开发一个电商网站后端接口还没准备好但你需要继续开发前端页面或者生产环境出现了一个奇怪的 bug你需要临时修改接口返回值来定位问题。这些情况下请求拦截就显得尤为重要。1.1 常见应用场景解析开发调试场景是最典型的需求。当后端接口尚未完成时前端开发者可以通过拦截请求返回 mock 数据保证开发进度不受影响。我曾在一次项目中使用拦截技术在后端接口延迟两周的情况下前端仍然按时完成了所有功能开发。线上问题排查是另一个重要用途。生产环境的接口出现问题但直接修改后端代码风险太大。通过请求拦截可以临时修改返回数据快速定位问题所在。记得有一次我们通过拦截请求发现了一个只在特定网络环境下才会出现的缓存问题。统一请求处理能显著提升代码质量。比如自动添加认证 Token统一处理错误码添加请求日志性能监控API 版本迁移浏览器扩展开发也离不开请求拦截。油猴脚本和 Chrome 扩展经常需要修改第三方网站的请求行为比如去除广告、修改数据展示等。1.2 现有方案的局限性传统上前端开发者需要分别处理 XMLHttpRequest (XHR) 和 Fetch API 两种请求方式。这带来了几个问题代码重复需要为两种 API 分别编写拦截逻辑兼容性问题不同库可能使用不同的请求方式比如 axios 使用 XHR而某些新库使用 Fetch功能缺失很多拦截库不支持流式响应处理侵入性强一些方案会污染全局对象可能影响其他代码2. ajax-hooker 核心功能解析2.1 统一拦截机制ajax-hooker 的核心价值在于它提供了一套统一的 API 来拦截和处理所有 AJAX 请求无论底层使用的是 XHR 还是 Fetch。这种设计带来了几个显著优势一致的开发体验开发者不需要关心请求的具体实现方式更少的代码量一套逻辑处理所有请求更好的可维护性集中管理请求拦截逻辑2.2 流式响应支持在现代 Web 应用中流式响应如 SSE、NDJSON变得越来越常见。ajax-hooker 的一个亮点是它对流式响应的完整支持interceptor.hook((request) { if (request.url.includes(/api/chat/stream)) { request.onStreamChunk (chunk) { console.log(收到数据块 #${chunk.index}:, chunk.text); return chunk.text.replace(敏感词, ***); }; } });这个功能在处理实时数据如聊天应用、股票行情、AI 生成内容时特别有用。2.3 细粒度的控制能力ajax-hooker 提供了非常细致的控制选项按类型拦截可以只拦截 XHR 或只拦截 Fetch链式钩子支持注册多个钩子函数按顺序执行完整请求/响应控制可以修改 URL、方法、头信息、请求体、响应数据等几乎所有方面3. 深度使用指南3.1 安装与基础配置ajax-hooker 提供了多种安装方式# npm npm install ajax-hooker # pnpm pnpm add ajax-hooker # CDN script srchttps://unpkg.com/ajax-hooker/script基础使用只需要三步import AjaxInterceptor from ajax-hooker; // 1. 获取单例实例 const interceptor AjaxInterceptor.getInstance(); // 2. 注入拦截 interceptor.inject(); // 3. 注册钩子函数 interceptor.hook((request) { // 拦截逻辑 });3.2 实战场景详解3.2.1 接口 Mockinginterceptor.hook((request) { request.response (resp) { if (request.url.includes(/api/products)) { resp.json [ { id: 1, name: Mock 商品, price: 99.99 } ]; resp.status 200; } }; });注意事项确保 mock 数据的结构与实际接口一致对于复杂接口可以考虑从外部文件加载 mock 数据生产环境应该移除 mock 逻辑3.2.2 统一认证处理interceptor.hook((request) { const token localStorage.getItem(auth_token); if (token) { request.headers.set(Authorization, Bearer ${token}); } });最佳实践将认证逻辑封装成独立钩子考虑 token 刷新机制对于特定路由可以跳过认证3.2.3 API 版本迁移interceptor.hook((request) { if (request.url.includes(/v1/)) { request.url request.url.replace(/v1/, /v2/); // 对于 POST 请求可能需要调整请求体 if (request.method POST) { request.data migrateV1ToV2(request.data); } } });迁移建议逐步迁移可以先重定向部分接口记录重定向日志方便排查问题考虑设置迁移超时时间3.3 性能监控实现interceptor.hook((request) { const startTime performance.now(); request.response (resp) { const duration performance.now() - startTime; reportMetrics({ url: request.url, method: request.method, status: resp.status, duration: duration }); if (duration 1000) { console.warn(慢请求: ${request.url} (${duration}ms)); } }; });监控要点使用 performance.now() 获取高精度时间考虑采样率避免产生太多数据可以添加请求大小监控4. 高级特性与原理4.1 底层实现机制ajax-hooker 的核心实现基于 ES6 Proxy这种设计带来了几个优势非侵入性不会污染原生对象原型细粒度控制可以拦截属性访问和方法调用更好的兼容性保持 instanceof 检查正常工作4.1.1 XHR 拦截实现function proxyXhr() { const xhr new nativeXHR(); return new Proxy(xhr, { get(target, prop) { // 拦截方法调用和属性访问 }, set(target, prop, value) { // 拦截属性设置 } }); }关键点使用 Symbol 存储内部状态处理 readystatechange 事件保持同步属性的一致性4.1.2 Fetch 拦截实现const originalFetch window.fetch; window.fetch async function(input, init) { // 规范化请求参数 // 执行钩子函数 // 调用原始 fetch // 处理响应 };复杂点处理各种输入格式URL 字符串、Request 对象流式响应处理保持 Promise 链完整4.2 多钩子协作机制ajax-hooker 支持注册多个钩子函数它们会按照注册顺序执行// 认证钩子 interceptor.hook(addAuthToken); // 日志钩子 interceptor.hook(logRequests); // 特定业务钩子 interceptor.hook(handleSpecialCases);执行规则请求阶段按注册顺序执行响应阶段按相反顺序执行可以通过返回 false 提前终止链式调用5. 常见问题与解决方案5.1 拦截不生效的可能原因注入时机太晚确保在页面加载早期就调用 inject()第三方库使用了自定义 HTTP 客户端有些库可能使用 WebSocket 或其他通信方式Service Worker 干扰Service Worker 可能优先拦截请求CORS 限制跨域请求可能无法被完全拦截5.2 性能优化建议减少不必要的拦截通过 URL 过滤减少处理量避免复杂的同步操作钩子函数应该尽量简单快速慎用全局拦截考虑按需注入和移除拦截器注意内存泄漏及时移除不再需要的钩子5.3 安全注意事项生产环境谨慎使用避免暴露敏感调试功能验证修改的数据防止注入攻击保护认证信息避免在日志中记录敏感头信息考虑撤销机制确保可以快速禁用所有拦截6. 与其他方案的对比6.1 功能比较特性ajax-hookerMSWaxios 拦截器拦截 XHR✓✓×拦截 Fetch✓✓×修改请求✓✓✓修改响应✓✓✓流式响应支持✓××不需要服务端配合✓×✓适合浏览器扩展✓××6.2 适用场景建议开发调试ajax-hooker 和 MSW 都适合但 ajax-hooker 更轻量生产环境功能ajax-hooker 是更好的选择浏览器扩展开发ajax-hooker 是唯一可行的方案测试环境MSW 可能更合适7. 最佳实践总结基于多个项目的实战经验我总结了以下最佳实践分层设计拦截逻辑将不同的拦截功能认证、日志、mock等分开开发环境增强可以添加请求标记和调试工具性能监控记录关键指标设置报警阈值文档化拦截规则团队共享拦截策略定期审查清理不再需要的拦截逻辑一个典型的项目结构可能如下/src /interceptors auth.js # 认证处理 logging.js # 请求日志 mock.js # 开发环境 mock metrics.js # 性能监控 index.js # 组合所有拦截器在 index.js 中import { authInterceptor } from ./auth; import { loggingInterceptor } from ./logging; import { metricsInterceptor } from ./metrics; export function setupInterceptors() { const interceptor AjaxInterceptor.getInstance(); interceptor.inject(); if (process.env.NODE_ENV development) { interceptor.hook(mockInterceptor); } interceptor.hook(authInterceptor); interceptor.hook(loggingInterceptor); interceptor.hook(metricsInterceptor); }这种结构使得拦截逻辑清晰可维护也方便在不同环境中启用不同的拦截策略。