[axios]实例没有全局拦截器

2024-08-22 834 views
0

我搜索了所有问题,并仔细检查了https://github.com/mzabriskie/axios/issues/812中引用的问题,但我的问题似乎有所不同。

我的问题是创建实例不会复制或使用添加到全局 Axios 的拦截器。

import Axios from "axios";

Axios.interceptors.request.use((config) => {
  console.log("Global Interceptor")
  return config;
});

const axiosInstance = () => {
  let instance = Axios.create();
  console.log(Axios.interceptors.request); // Has 1
  console.log(instance.interceptors.request); // Has 0
  return instance;
}

axiosInstance().post("/test", { testing: "data" }); // Doesn't output "Global Interceptor"
Axios.post("/test", { testing: "data" }); // Outputs "Global Interceptor"
 语境
  • Axios 版本:0.16.2
  • 环境:Webpack 2.6.1,Chrome Canary 61.0.3147.0,Mac OS X

回答

4

这更像是一个功能,而不是一个错误(因为在这种情况下的行为没有记录)。如果我们实现这一点,我们应该首先回答(并记录)一些问题:

  • 全局拦截器是在运行时被实例继承还是在创建时被复制?
  • 如果它们在运行时被继承,那么拦截器的顺序应该是什么?

我们可以对实例的其余部分与全局默认值提出同样的问题,因为大多数情况下不存在顺序因素。

@mzabriskie,@nickuraltsev:有什么想法吗?

4

@rubennorte 我建议不要添加 的功能global interceptors。那么如何扩展现有的 axios 实例呢?这样开发人员就可以准确地知道哪些拦截器和选项是继承或扩展的:

import axios from 'axios';

export const api = axios.create({
  baseURL: process.env.API_ROOT,
});

api.interceptors.request.use((request) => {
  request.headers.Authorization = `Bearer mytoken`;
  return request;
});

// Here the pdfInstance extends the api instance so the pdfInstance has also access to the request interceptor but is also able to override the baseURL and adding additional header such as Accept
export const pdfInstance = api.extend({
  baseURL: '/file',
  responseType: 'arraybuffer',
  headers: {
    Accept: 'application/pdf',
  },
});
5

我同意 @bierik 的观点,能够扩展现有实例确实很棒,尽管排序是个问题。我认为最安全的做法是继承扩展的拦截器,如果您覆盖它们,它们将不再触发。不过,可以选择触发以前的拦截器,类似于 super() 调用,这很好。这允许开发人员控制排序。

8

那么,如何使用便捷函数从现有实例中提取拦截器呢?

// from the default instance
let api = axios.create({baseUrl:"http://internal.mycompany.com"});
api.interceptors.assimilate(axios);

// or from another created instance
let thirdParty = axios.create({baseUrl:"https://partner.example.com"});
thirdParty.interceptors.assimilate(api);

最重要的是,您可以使用配置选项明确地从默认实例中提取拦截器:

let api = axios.create({defaultInterceptors:true});
3

请添加此功能!

7

请添加此功能!我不想复制,拜托

2

有什么更新吗?

4

你好,我想知道这个扩展方法该如何实现。

0

有任何最新消息吗?

6

同意https://github.com/axios/axios/issues/993#issuecomment-335095893。用户可以轻松重用全局拦截器,而无需任何冗余代码,只要将它们保存在单独的文件中即可。以下是示例代码,

// wrapper.js
const interceptors = [
  [f11, f12], // pair of successful and failed handlers
  [f21, f22]
];

exports.default = function(chain) {
  interceptors.forEach(([f1, f2]) => chain.use(f1, f2));
};

// index.js
const wrapper = require('./wrapper');

wrapper(axios.interceptors.request);
wrapper(axios.create(config).interceptors.request);
7

我是这样解决的(对 _ 使用 lodash):

// axios.create creates a new Axios object that does not copy the global interceptors
// this override fixes that
const orgCreate = axios.create;
axios.create = function (config?: AxiosRequestConfig): AxiosInstance {
    const result = orgCreate.call(this, config);
    _.forEach((axios.interceptors.request as any).handlers, (handler) => {
        result.interceptors.request.use(handler.fulfilled, handler.rejected);
    });
    _.forEach((axios.interceptors.response as any).handlers, (handler) => {
        result.interceptors.response.use(handler.fulfilled, handler.rejected);
    });
    return result;
}
3

感谢 nelisbijl,游戏保护程序运行得很好。

6

谢谢@nelisbijl 我采用了你的解决方案并添加了继承类型行为(包括“使用”和“弹出”)。如果有人也觉得这有用。还将其包装在 NPM 模块axios-inherit:中以方便使用

  1. 创建新的 axios 实例时“继承”全局 axios 实例的任何现有拦截器。
  2. 向全局 axios 实例添加拦截器时,将新的拦截器应用于现有实例。
  3. 对拦截器的移除应用相同的行为(弹出)
const { create } = axios;
const instances = [];

// new instances "inherit" existing interceptors
axios.create = function (...args) {
  const instance = create.apply(this, args);
  instances.push(instance);

  for (const type in axios.interceptors) {
    axios.interceptors[type].handlers.forEach(
      ({ fulfilled, rejected }) => instance.interceptors[type].use(fulfilled, rejected)
    );
  }

  return instance;
};

// new interceptors are being "inherited" to existing instances
for (const type in axios.interceptors) {
  ['eject', 'use'].forEach(
    method => {
      const original = axios.interceptors[type][method];

      axios.interceptors[type][method] = function (...args) {
        const result = original.apply(axios.interceptors[type], args);
        instances.forEach(
          instance => instance.interceptors[type][method](...args)
        );
        return result;
      };
    }
  );
}
9

这有效。但有些不对劲。全局拦截器被添加到一个不是通过重写的 create 函数创建的 axios 实例中。最后为了修复它,在重写的 create 函数中,我使用了一个自定义配置参数来决定是否添加全局拦截器。