当前位置:首页 > 问答 > 正文

ajax 前端 全局拦截所有ajax请求的方法与实现

拦截所有AJAX请求:前端开发中的全局管控技巧

场景引入:那些年我们踩过的AJAX坑

小王最近接手了一个老项目,发现页面里到处散落着重复的AJAX错误处理逻辑:

$.ajax({  
  error: function(xhr) {  
    if(xhr.status === 401) {  
      alert('登录过期啦!')  
      jumpToLogin()  
    }  
  }  
})  

更糟的是,不同开发者写的错误提示样式五花八门——有的用alert,有的用Toast,还有的直接在页面角落塞个红色小字,这时候如果能统一拦截所有AJAX请求,就像给整个项目装上"中央空调",那该多清爽?

拦截原理:改写XMLHttpRequest原型

所有现代AJAX库(包括jQuery/axios)底层都基于浏览器原生XMLHttpRequest对象,我们只需要"劫持"它的open()send()方法:

const originalOpen = XMLHttpRequest.prototype.open  
const originalSend = XMLHttpRequest.prototype.send  
XMLHttpRequest.prototype.open = function(method, url) {  
  console.log(`拦截到请求:${method} ${url}`)  
  // 在这里可以添加全局请求头等操作  
  this.setRequestHeader('X-Requested-With', 'CustomAJAX')  
  return originalOpen.apply(this, arguments)  
}  
XMLHttpRequest.prototype.send = function(body) {  
  const startTime = Date.now()  
  this.addEventListener('loadend', () => {  
    console.log(`请求耗时:${Date.now() - startTime}ms`)  
  })  
  return originalSend.apply(this, arguments)  
}  

实战方案:完整拦截器实现

基础版(支持错误监控)

(function() {  
  const originalFetch = window.fetch  
  const originalXHR = window.XMLHttpRequest  
  // 拦截Fetch API  
  window.fetch = async function(...args) {  
    try {  
      const start = Date.now()  
      const response = await originalFetch(...args)  
      console.log(`[FETCH] ${args[0]} 耗时${Date.now() - start}ms`)  
      return response  
    } catch (err) {  
      handleError(err)  
      throw err  
    }  
  }  
  // 拦截XMLHttpRequest  
  window.XMLHttpRequest = class extends originalXHR {  
    open(method, url) {  
      this._method = method  
      this._url = url  
      super.open(method, url)  
    }  
    send(data) {  
      this._startTime = Date.now()  
      this.addEventListener('loadend', () => {  
        const duration = Date.now() - this._startTime  
        if (this.status >= 400) {  
          handleError(new Error(`${this._method} ${this._url} ${this.status}`))  
        }  
        console.log(`[XHR] ${this._url} 耗时${duration}ms`)  
      })  
      super.send(data)  
    }  
  }  
  function handleError(err) {  
    console.error('全局捕获AJAX错误:', err)  
    // 这里可以统一展示错误提示  
    showToast('网络请求失败,请稍后重试')  
    // 上报错误到监控系统  
    reportToMonitor(err)  
  }  
})()  

高级功能扩展

  1. 请求耗时统计
    const apiPerformance = {}  

function recordApiTime(url, cost) {
if (!apiPerformance[url]) {
apiPerformance[url] = { count: 0, total: 0 }
}
apiPerformance[url].count++
apiPerformance[url].total += cost
}

ajax 前端 全局拦截所有ajax请求的方法与实现

// 在拦截器中调用
recordApiTime(url, Date.now() - startTime)


2. **自动重试机制**  
```javascript  
const MAX_RETRY = 2  
function enhancedFetch(url, options = {}, retryCount = 0) {  
  return fetch(url, options).catch(err => {  
    if (retryCount < MAX_RETRY && isRetryable(err)) {  
      return enhancedFetch(url, options, retryCount + 1)  
    }  
    throw err  
  })  
}  
function isRetryable(err) {  
  return err.message.includes('timeout') ||  
         err.message.includes('Network Error')  
}  

各框架的优雅实现

axios拦截器方案

axios.interceptors.request.use(config => {  
  config.headers['X-Trace-Id'] = generateUUID()  
  return config  
})  
axios.interceptors.response.use(  
  response => response,  
  error => {  
    if (error.response?.status === 401) {  
      router.push('/login')  
    }  
    return Promise.reject(error)  
  }  
)  

jQuery全局设置

$.ajaxSetup({  
  beforeSend: function(xhr) {  
    xhr.setRequestHeader('X-CSRF-TOKEN', getCSRFToken())  
  },  
  error: function(xhr) {  
    if (xhr.status === 403) {  
      showPermissionDeniedModal()  
    }  
  }  
})  

注意事项

  1. 执行顺序问题
    拦截器代码必须放在其他业务代码之前执行,建议作为第一个加载的脚本

  2. 避免循环调用
    在错误处理中慎用AJAX请求,可能导致无限循环

  3. 性能影响
    高频请求场景建议精简拦截逻辑,或用条件判断跳过非必要处理

    ajax 前端 全局拦截所有ajax请求的方法与实现

  4. TypeScript支持
    如果需要类型提示,可以扩展全局接口:

    declare global {  
      interface XMLHttpRequest {  
        _method: string  
        _url: string  
        _startTime: number  
      }  
    }  

全局拦截就像给AJAX请求装上了行车记录仪,既能统一处理共性需求(如错误提示、日志记录),又能灵活扩展个性化功能(如接口耗时统计、自动重试),下次当你发现项目里有重复的AJAX处理逻辑时,不妨试试这套"中央管控"方案,让代码更加干净利落。

(本文实现方案基于2025年8月主流浏览器API标准)

发表评论