Axios 使用拦截器重试失败的请求不起作用

时间:2021-02-13 01:24:02

标签: javascript node.js axios

在这个问题上尝试了 50 多个小时后,我终于放弃了。我在谷歌上搜索了很多,但只能找到对我不起作用的小部分。

我正在使用 NodeJS 和 Axios 发出 API 请求。有 3 次请求失败,我想在放弃之前重试请求 3 次。

  • 网络错误(未登录 axios)
  • 服务器错误(状态代码 50x、40x 等)
  • CORS 错误

我有一个 apiClient 和 apiCalls 类。

我想捕获所有问题并在 apiClient 中重试。

这是我到目前为止所拥有的,在尝试了 30 多个解决方案后,我无法使其正常工作。重试请求尝试只会运行一次,然后错误将杀死它。

apiClient.js:

import axios from 'axios'
import qs from 'querystring'
import config from '../../config/config'

const api = axios.create({
  baseURL: config.api.baseUrl,
  headers: {
    'X-User-Agent': 'API Client ' + config.version,
    Accept: 'application/json',
    'Content-Type': 'application/json'
  },
  params: {
    user: config.api.user
  }
})

api.interceptors.request.use(request => {
  console.log(`apiClient (${request.method.toUpperCase()}) URL: ${request.baseURL}${request.url}?` + qs.stringify(request.params))
  return request
})

api.interceptors.response.use(
  async response => successHandler(response),
  async error => errorHandler(error)
)

const errorHandler = async (error) => {

  const originalRequest = error.config

  // Assume possible CORS error when response is empty
  if (typeof error.response === 'undefined') {
    console.warn(`apiClient: Caught possible CORS error!`)
    return await retryRequest(originalRequest)
  }
  
  if (error.response) {
    console.warn(`apiClient: FATAL ERROR DETECTED! (HTTP STATUS ${error.response.status}): ${error.request.responseURL}`)
    return await retryRequest(originalRequest)
  }
  
  // Assuming network error if no HTTP error code
  if (isNetworkError(error)) {
    console.warn('apiClient: NETWORK ERROR DETECTED!')
    return await retryRequest(originalRequest)
    
  }

  return Promise.reject(error)
}

const SUCCESS_STATUS_CODES = [
  200,
  204
]

const successHandler = (response) => {
  if (!SUCCESS_STATUS_CODES.includes(response.status)) {
    console.log(`successHandler status failed (${response.status}): ${response.request.responseURL}`)
  } else {
    console.log(`API Response Success (${response.status}): ${response.request.responseURL}`)
  }

  return response
}

async function retryRequest (request) {
  let retryAttempts = 3
  for (let retryAttempt = 0; retryAttempt < retryAttempts; retryAttempt++) {
    console.warn('Retrying request attempt: ' + (retryAttempt + 1))

    return this.transport.request({
      method: request.config.method,
      url: request.config.url,
      params: request.config.params,
      withCredentials: true,
    })
  }
}

function isNetworkError (err) {
  return !!err.isAxiosError && !err.response
}

export {
  apiClient
}

apiCalls.js 示例:

const version = config.api.version
const datasource = config.api.datasource

class ApiCalls {

  async getMarketOrders (regionId, typeId = null) {

  const results = []

  try {

    const response = await api.get(`${version}/markets/${regionId}/orders/`, {
      params: {
        type_id: typeId
      }
    })

  } catch (e) {
    throw new Error(this.errorHandler('getMarketOrders', e))
  }

  errorHandler (functionName, error) {
    return JSON.stringify({ function: functionName, error: error })
  }
}

export default ApiCalls

这是在一个函数中调用的:

let regionOrders = await apiClient.getMarketOrders(regionId, typeId)

我尝试了无数不支持网络错误的重试库,仅支持 HTTP 状态代码,因此它们对我不起作用。

谢谢。

0 个答案:

没有答案