如何使用适配器在Axios中更改结果状态?

时间:2019-12-18 23:01:00

标签: node.js axios adapter axios-retry

原因

我们正在使用axios-retry库,该库在内部使用以下代码:

axios.interceptors.response.use(null, error => {

由于它仅指定错误回调,因此Axios documentation说:

  

任何状态代码超出2xx范围都会触发此功能

不幸的是,我们正在调用一个非RESTful API,该API可以在主体中返回200并带有错误代码,我们需要重试。

我们已经尝试在axios-retry之前添加Axios拦截器,并在这种情况下更改结果状态。但这并不会触发后续的拦截器错误回调。

did 的工作是指定自定义适配器。但是,这没有充分的文档证明,我们的代码无法处理所有情况。

代码

const axios = require('axios');
const httpAdapter = require('axios/lib/adapters/http');
const settle = require('axios/lib/core/settle');
const axiosRetry = require('axios-retry');

const myAdapter = async function(config) {
  return new Promise((resolve, reject) => {
    // Delegate to default http adapter
    return httpAdapter(config).then(result => {
      // We would have more logic here in the production code
      if (result.status === 200) result.status = 500;
      settle(resolve, reject, result);
      return result;
    });
  });
}

const axios2 = axios.create({
  adapter: myAdapter
});

function isErr(error) {
  console.log('retry checking response', error.response.status);
  return !error.response || (error.response.status === 500);
}

axiosRetry(axios2, {
  retries: 3,
  retryCondition: isErr
});

// httpstat.us can return various status codes for testing
axios2.get('http://httpstat.us/200')
  .then(result => {
    console.log('Result:', result.data);
  })
  .catch(e => console.error('Service returned', e.message));

这在错误情况下有效,打印:

retry checking response 500
retry checking response 500
retry checking response 500
retry checking response 500
Service returned Request failed with status code 500

它也可以在成功的情况下起作用(将URL更改为http://httpstat.us/201):

Result: { code: 201, description: 'Created' }

问题

将URL更改为http://httpstat.us/404会导致:

(node:19759) UnhandledPromiseRejectionWarning: Error: Request failed with status code 404
    at createError (.../node_modules/axios/lib/core/createError.js:16:15)
    at settle (.../node_modules/axios/lib/core/settle.js:18:12)

catch调用中的httpAdapter会捕获该错误,但是如何将其传递给链下?

实现Axios适配器的正确方法是什么?

如果有更好的方法来解决这个问题(不使用axios-retry库,则可以接受)。

更新

一位同事发现,在.catch(e => reject(e))通话中执行.catch(reject)(或仅httpAdapter)似乎可以解决此问题。但是,我们仍然希望有一个规范的示例来实现一个包装了默认http适配器的Axios适配器。

1 个答案:

答案 0 :(得分:1)

这是起作用的(在节点中):

const httpAdapter = require('axios/lib/adapters/http');
const settle = require('axios/lib/core/settle');

const customAdapter = config =>
  new Promise((resolve, reject) => {
    httpAdapter(config).then(response => {
      if (response.status === 200)
        // && response.data contains particular error
      {
        // log if desired
        response.status = 503;
      }
      settle(resolve, reject, response);
    }).catch(reject);
  });

// Then do axios.create() and pass { adapter: customAdapter }
// Now set up axios-retry and its retryCondition will be checked