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

u4vypkhs  于 12个月前  发布在  Node.js
关注(0)|答案(3)|浏览(112)

为什么

我们使用axios-retry库,它在内部使用以下代码:
第一个月
由于它只指定了错误回调,Axios文档说:
任何超出2xx范围的福尔斯状态代码都会触发此功能
不幸的是,我们正在调用一个非REST风格的API,它可能会返回200,并在主体中返回一个错误代码,我们需要重试。
我们尝试在axios-retry之前添加一个Axios拦截器,并在本例中更改结果状态;但这并没有触发后续的拦截器错误回调。
真正起作用的是指定一个自定义适配器。然而,这并没有很好的文档记录,我们的代码并不能处理每一种情况。

代码

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)


httpAdapter调用上的catch将捕获该错误,但我们如何将其传递到链的下游?
实施Axios适配器的正确方法是什么?
如果有更好的方法来处理这个问题(除了分叉axios-retry库),这将是一个可以接受的答案。

更新

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

1tuwyuhd

1tuwyuhd1#

以下是工作原理(在node中):

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

字符串

dphi5xsq

dphi5xsq2#

使用拦截器和自定义错误的解决方法

const axios = require("axios").default;
const axiosRetry = require("axios-retry").default;

axios.interceptors.response.use(async (response) => {
  if (response.status == 200) {
    const err = new Error("I want to retry");
    err.config = response.config; // axios-retry using this
    throw err;
  }
  return response;
});

axiosRetry(axios, {
  retries: 1,
  retryCondition: (error) => {
    console.log("retryCondition");
    return false;
  },
});

axios
  .get("https://example.com/")
  .catch((err) => console.log(err.message)); // gonna be here anyway as we'll fail due to interceptor logic

字符串

rjee0c15

rjee0c153#

如果您的应用程序在浏览器环境中运行,则应使用axios内置的XHR适配器。

import xhrAdapter from 'axios/lib/adapters/xhr';
import settle from 'axios/lib/core/settle';

function customAdapter(config: AxiosRequestConfig): any {
  return new Promise((resolve, reject) => {
    xhrAdapter(config)
      .then((response: AxiosResponse) => {
        if (xxx) {
          response.status = 401;
        }
        settle(resolve, reject, response);
      })
      .catch(reject);
  });
}

字符串

相关问题