【问题标题】:Catch axios requests in different files / functions在不同的文件/函数中捕获 axios 请求
【发布时间】:2025-12-04 23:25:01
【问题描述】:

我使用 HTTP 请求为我的 Vue.js 应用程序获取数据。我有一个名为 Api.js 的文件,其中包含基本 axios 实例:

export default () => {
  return axios.create({
    baseURL: apiURL,
    headers: {
      Authorization: `JWT ${store.state.token}`
    }
  })
}

我有一个名为 service.js 的文件,其中包含不同端点的函数:

export default {
  status() {
    return Api().get('status/')
  }
}

.vue 文件中我这样调用方法。

created() {
  Service.status()
    .then(response => {
      // do something with the data
    })
    .catch(e => {
      // show exception
    })
}

一些异常应该在Api.js中处理(例如:401),其他一些异常应该在service.js中处理,其他的在中.vue 文件。我该怎么做?

【问题讨论】:

    标签: javascript vue.js exception-handling axios es6-promise


    【解决方案1】:

    免责声明:我创建了两个小型 axios 插件来轻松实现这种特定模式。

    axios-middleware

    简单的 axios HTTP 中间件服务,用于简化对通过 Axios 发出的 HTTP 请求的挂钩。

    它使用 axios 拦截器作为 mentioned by acdcjunior,但它使用众所周知的中间件模式抽象了 axios 的使用,因此您的应用不需要了解和处理拦截器语法。

    // import your API's axios instance
    import http from './api';
    import { Service } from 'axios-middleware';
    
    // Create a new service instance
    const service = new Service(http);
    
    // We're good to go!
    export default service;
    

    然后,您可以使用此中间件服务在应用中的任何位置注册不同的中间件。中间件可以像对象一样简单,也可以是可重用、易于测试的类。

    import i18n from './services/i18n';
    import toast from './services/toast';
    import service from './services/middleware';
    import { ApiErrorMiddleware, OtherMiddleware } from './middlewares';
    
    
    // Then register your middleware instances.
    service.register([
        // Middleware class instance
        new ApiErrorMiddleware(i18n, toast),
        new OtherMiddleware(),
        // or a simple object
        {
            onRequest() {
                // handle the request
            },
            onResponseError(error) {
                // handle the response error
            }
        }
    ]);
    

    ApiErrorMiddleware 是一个简单的类,仅负责在错误时显示 toast 消息。

    export default class ApiErrorMiddleware {
        /**
         * @param {VueI18n} i18n instance
         * @param {Object} toast message service
         */
        constructor(i18n, toast) {
            this.toast = toast;
            this.i18n = i18n;
        }
    
        /**
         * @param {Object} error
         */
        onResponseError(error = {}) {
            const { response } = error;
            let key = 'errors.default';
    
            if (response && this.i18n.te(`errors.${response.status}`)) {
                key = `errors.${response.status}`;
            } else if (error.message === 'Network Error') {
                key = 'errors.network-error';
            } else {
                // TODO log unhandled errors
            }
            this.toast.error(this.i18n.t(key));
        }
    }
    

    axios-resource

    简单的 axios 资源类,可轻松与 REST 端点交互。

    定义一个资源类。在这里,我添加了 onErroronFetchError 作为您的用例示例。

    import Resource from 'axios-resource';
    
    export default class UserResource extends Resource {
        static URL = 'user/{id}';
    
        // This calls `sync` in the background
        fetch() {
            return super.fetch.apply(this, arguments)
                .catch(err => this.onFetchError(err));
        }
    
        onFetchError(err) {
            // An error occurred while fetching this resource.
        }
    
        onError(err) {
            // An error occurred with this resource
        }
    
        // called for every actions (fetch, create, patch, delete)
        sync() {
            return super.sync.apply(this, arguments)
                .catch((err) => this.onError(err))
        }
    }
    

    然后,在api.js 中创建一个实例。

    import UserResource from './user';
    
    const user = new UserResource();
    
    // GET https://example.com/api/user/me
    user.fetch('me')
        .then(({ data }) => {
            console.log('User data:', data);
        });
    

    可以在每一步处理错误。

    1. 在此特定资源的onFetchError
    2. 在此资源的onError
    3. 在应用的中间件中。

    【讨论】:

      【解决方案2】:

      你应该添加axios interceptors:

      Axios 拦截器

      您可以在请求或响应被处理之前拦截它们 thencatch

      // 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);
        });
      

      那些可以(应该)在你的 Api.js 中。

      【讨论】: