乐闻世界logo
搜索文章和话题

Axios 如何使用拦截器?

9 个月前提问
5 个月前修改
浏览次数69

6个答案

1
2
3
4
5
6

Axios 拦截器允许我们在请求或响应被 then 或者 catch 处理之前对它们进行拦截和修改。拦截器通常用于以下几个目的:

  1. 在请求发送到服务器之前对请求数据进行修改。
  2. 发送请求前,在请求头中附加认证信息(如JWT令牌)。
  3. 在请求到达服务器之前取消请求。
  4. 统一处理所有的响应错误。
  5. 在响应数据到达应用逻辑之前对数据进行转换。

使用 Axios 拦截器主要有两种类型:请求拦截器和响应拦截器。

添加请求拦截器

请求拦截器会在请求真正发送出去之前执行。以下是添加请求拦截器的一般方法:

javascript
// 添加请求拦截器 axios.interceptors.request.use(function (config) { // 在发送请求之前做些什么,例如设置token config.headers.Authorization = `Bearer ${YOUR_AUTH_TOKEN}`; return config; }, function (error) { // 对请求错误做些什么 return Promise.reject(error); });

在这里,我们首先使用 axios.interceptors.request.use 添加了一个请求拦截器。这个拦截器接收两个函数作为参数,第一个函数会在请求发出前被调用,并接收请求的配置对象 config 作为参数,允许我们修改这个配置对象。在上面的例子中,我们添加了一个 Authorization 头,其值是一个假设的认证令牌 YOUR_AUTH_TOKEN。第二个函数是当请求出现错误时执行,这里我们简单地将错误返回。

添加响应拦截器

响应拦截器会在服务器的响应数据到达 thencatch 之前被调用。以下是添加响应拦截器的一般方法:

javascript
// 添加响应拦截器 axios.interceptors.response.use(function (response) { // 对响应数据做点什么 // 可以根据你的需求来对响应数据做处理,这里只是一个示例 if (response.data && response.data.success) { return response.data.data; } else { // 你可以在这里处理不成功的情况,或者抛出一个错误 return Promise.reject('Error with request'); } }, function (error) { // 对响应错误做点什么 if (error.response.status === 401) { // 如果状态码是 401,可以进行重新登录等处理 } return Promise.reject(error); });

在这个例子中,我们使用 axios.interceptors.response.use 添加了一个响应拦截器。它也接收两个函数,第一个函数在响应正确返回时被调用,接收响应对象 response 作为参数。在这个函数中,我们做了一些简单的判断,并只返回了实际需要的数据部分。第二个函数在响应出现错误时被调用,例如可以在这里处理 401 Unauthorized 状态码,实现自动重新登录或者跳转到登录页面等操作。

移除拦截器

如果你想在某个时刻移除拦截器,你可以这样做:

javascript
// 添加拦截器时会返回一个拦截器的ID const myInterceptor = axios.interceptors.request.use(function () {/*...*/}); // 通过这个ID可以移除拦截器 axios.interceptors.request.eject(myInterceptor);

在上面的代码中,我们首先添加了一个请求拦截器,并将返回的拦截器 ID 保存在 myInterceptor 变量中。然后,我们调用 axios.interceptors.request.eject 方法并传入这个 ID 来移除拦

2024年6月29日 12:07 回复

简单来说,它更像是每个 HTTP 操作的检查点。已进行的每个 API 调用都会通过此拦截器传递。

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

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

一些请求拦截器用例 -

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

假设您需要为每个发出的请求附加一个令牌,而不是在每次 Axios 调用时重复令牌添加逻辑,您可以创建一个拦截器,在发出的每个请求上附加一个令牌。

一些响应拦截器用例 -

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

假设您已使用有效的 API 凭据请求了某些 API,但您没有访问数据的有效角色。因此,您可以从响应拦截器触发警报,表示不允许该用户。这样,您就可以避免必须对您发出的每个 Axios 请求执行未经授权的 API 错误处理。

这是一些代码示例

请求拦截器

  • 可以通过执行以下操作(在本例中,通过检查环境变量)打印 axios 的配置对象(如果需要):

    shell
    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对象中使用。例如:

    shell
    axios.interceptors.request.use((config) => { config.headers.genericKey = "someGenericValue"; return config; }, (error) => { return Promise.reject(error); });
  • 如果是请求GET,则可以在对象中找到发送的查询参数config.params

响应拦截器

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

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

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

    shell
    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代码,然后做出决定。例如:

    shell
    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); });
2024年6月29日 12:07 回复

例如,如果您想捕获从发送请求到收到响应所花费的时间,您可以使用此代码:

shell
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); }); })();
2024年6月29日 12:07 回复

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

看看这个:axios拦截器和异步登录

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

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

2024年6月29日 12:07 回复

我将为您提供我在现实项目中使用的更多实际用例。我通常使用,request interceptor对于与令牌相关的人员(accessTokenrefreshToken),例如,令牌是否未过期,如果是,则使用refreshToken更新它并保留所有其他调用直到它解决。但我最喜欢的是 axios,response interceptors您可以在其中放置应用程序的全局错误处理逻辑,如下所示:

shell
httpClient.interceptors.response.use( (response: AxiosResponse) => { // Any status code that lie within the range of 2xx cause this function to trigger return response.data; }, (err: AxiosError) => { // Any status codes that falls outside the range of 2xx cause this function to trigger const status = err.response?.status || 500; // we can handle global errors here switch (status) { // authentication (token related issues) case 401: { return Promise.reject(new APIError(err.message, 409)); } // forbidden (permission related issues) case 403: { return Promise.reject(new APIError(err.message, 409)); } // bad request case 400: { return Promise.reject(new APIError(err.message, 400)); } // not found case 404: { return Promise.reject(new APIError(err.message, 404)); } // conflict case 409: { return Promise.reject(new APIError(err.message, 409)); } // unprocessable case 422: { return Promise.reject(new APIError(err.message, 422)); } // generic api error (server related) unexpected default: { return Promise.reject(new APIError(err.message, 500)); } } } );
2024年6月29日 12:07 回复

我已经通过以下方式实现了

httpConfig.js

shell
import axios from 'axios' import { baseURL } from '../utils/config' import { SetupInterceptors } from './SetupInterceptors' const http = axios.create({ baseURL: baseURL }) SetupInterceptors(http) export default http

安装拦截器.js

shell
import { baseURL } from '../utils/config' export const SetupInterceptors = http => { http.interceptors.request.use( config => { config.headers['token'] = `${localStorage.getItem('token')}` config.headers['content-type'] = 'application/json' return config }, error => { return Promise.reject(error) } ) http.interceptors.response.use(function(response) { return response }, function (error) { const status = error?.response?.status || 0 const resBaseURL = error?.response?.config?.baseURL if (resBaseURL === baseURL && status === 401) { if (localStorage.getItem('token')) { localStorage.clear() window.location.assign('/') return Promise.reject(error) } else { return Promise.reject(error) } } return Promise.reject(error) }) } export default SetupInterceptors

参考:链接

2024年6月29日 12:07 回复

你的答案