如何使用axios拦截器?


78

我看过axios文档,但它说的只是

// Add a request interceptor
axios.interceptors.request.use(function (config) {
    // Do something before request is sent
    return config;
  }, function (error) {
    // Do something with request error
    return Promise.reject(error);
  });

// Add a response interceptor
axios.interceptors.response.use(function (response) {
  // Do something with response data
  return response;
}, function (error) {
  // Do something with response error
  return Promise.reject(error);
});

同样,许多教程仅显示此代码,但是我很困惑它的用途,有人可以给我简单的示例进行操作。

Answers:


112

简单来说,它是每个http操作的一个检查点。进行的每个api调用都会通过此拦截器传递。

那么,为什么要使用两个拦截器?

api调用由两个部分组成:一个请求和一个响应。由于它的行为类似于检查点,因此请求和响应具有单独的拦截器。

一些请求拦截器用例-

假设您要在发出请求之前进行检查,您的凭证有效吗?因此,您可以在拦截器级别检查您的凭据是否有效,而不是实际进行api调用。

假设您需要在每个请求上附加一个令牌,而不是在每个axios调用中复制令牌添加逻辑,您可以制作一个拦截器,在每个请求上附加一个令牌。

一些响应拦截器用例-

假设您有一个响应,并根据您想推断用户已登录的api响应进行判断。因此,在响应拦截器中,您可以初始化一个处理用户登录状态的类,并在响应对象上相应地对其进行更新。收到。

假设您请求了一些具有有效api凭据的api,但是您没有访问数据的有效角色。因此,您可以从响应拦截器发出警告,说不允许该用户。这样,您就可以避免必须对每个axios请求执行的未经授权的api错误处理。

现在可以提出这些用例。

希望这可以帮助 :)

编辑

由于此答案越来越受欢迎,因此这里有一些代码示例

请求拦截器

=>可以这样做(在这种情况下,通过检查环境变量)来打印axios的配置对象(如果需要):

const DEBUG = process.env.NODE_ENV === "development";

axios.interceptors.request.use((config) => {
    /** In dev, intercepts request and logs it into console for dev */
    if (DEBUG) { console.info("✉️ ", config); }
    return config;
}, (error) => {
    if (DEBUG) { console.error("✉️ ", error); }
    return Promise.reject(error);
});

=>如果要检查正在传递的标头/添加更多通用标头,则该标头在config.headers对象中可用。例如:

axios.interceptors.request.use((config) => {
    config.headers.genericKey = "someGenericValue";
    return config;
}, (error) => {
    return Promise.reject(error);
});

=>如果是GET请求,则可以在config.paramsobject中找到正在发送的查询参数。

响应拦截器

=>您甚至可以选择在拦截器级别解析api响应,并将解析后的响应向下传递而不是原始响应。如果在多个地方以相同的方式使用api,可能会节省您一次又一次地编写解析逻辑的时间。一种方法是在中传递一个额外的参数,api-request然后在响应拦截器中使用相同的参数来执行操作。例如:

//Assume we pass an extra parameter "parse: true" 
axios.get("/city-list", { parse: true });

一次,在响应拦截器中,我们可以像这样使用它:

axios.interceptors.response.use((response) => {
    if (response.config.parse) {
        //perform the manipulation here and change the response object
    }
    return response;
}, (error) => {
    return Promise.reject(error.message);
});

因此,在这种情况下,只要中有一个parse对象response.config,便会完成操作,在其他情况下,它将照常工作。

=>您甚至可以查看到达的HTTP代码,然后做出决定。例如:

axios.interceptors.response.use((response) => {
    if(response.status === 401) {
         alert("You are not authorized");
    }
    return response;
}, (error) => {
    if (error.response && error.response.data) {
        return Promise.reject(error.response.data);
    }
    return Promise.reject(error.message);
});

1
您将这些拦截器写在哪里-在每个组件上还是整个应用程序的全局/中央位置?
James Poulose

@JamesPoulose应该放在中央位置,因为它的行为非常简单。它也可以在组件级别编写,但这通常会导致代码重复。这不是明智的选择
Aseem Upadhyay

1
@JamesPoulose,您可以分离出服务层,并在该服务层的基础上设置拦截器,例如services/index.js。因此前端应用程序停留在一个位置,并且服务保持分离并且与平台无关:D
Aseem Upadhyay

1
@AseemUpadhyay我把这个代码services/index.jsexport default axios,然后import axios from "services/index.js",无论我用爱可信。但是我看到互联网上的其他人改为为axios创建包装器……您个人使用哪种方法?谢谢
拉吉

1
@JamesPoulose我通过在“ src”文件夹下创建“ services”文件夹解决了此问题。在此目录中,我将创建一个“ request.js”或用于编写拦截器的任何自定义名称。
novonimo

17

它就像一个中间件,基本上可以添加到任何请求(无论是GET,POST,PUT,DELETE)还是任何响应(从服务器获得的响应)上。它通常用于涉及授权的情况。

看一下:Axios拦截器和异步登录

这是另一篇关于此的文章,并带有不同的示例:https : //medium.com/@danielalvidrez/handling-error-responses-with-grace-b6fd3c5886f0

因此,其中一个示例的要点是,您可以使用拦截器来检测您的授权令牌是否已过期(例如,如果您获得403)并重定向页面。


6

例如,如果要捕获从发送请求到收到响应之间的时间,可以使用此代码:

const axios = require("axios");

(async () => {
  axios.interceptors.request.use(
    function (req) {
      req.time = { startTime: new Date() };
      return req;
    },
    (err) => {
      return Promise.reject(err);
    }
  );

  axios.interceptors.response.use(
    function (res) {
      res.config.time.endTime = new Date();
      res.duration =
        res.config.time.endTime - res.config.time.startTime;
      return res;
    },
    (err) => {
      return Promise.reject(err);
    }
  );

  axios
    .get("http://localhost:3000")
    .then((res) => {
      console.log(res.duration)
    })
    .catch((err) => {
      console.log(err);
    });
})();

1
我赞成您的回答,因为您将拦截器和实际呼叫显示在一个地方。我很难把两者放在一起。
Wood夫
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.