You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel+Vue.js SPA中Axios错误处理的优化方案咨询

兄弟,我完全懂你的痛点——之前在Laravel+Vue的SPA项目里,每个Vuex Action都写一遍try/catch处理Axios错误,不仅代码冗余到爆炸,还经常漏掉一些统一的错误场景,比如401过期跳转、Laravel的验证错误提示这些。我后来摸索出几个实用的方案,分享给你:

1. 全局Axios拦截器(最推荐)

这是我现在最常用的方案,在Axios实例里添加响应拦截器,把所有错误逻辑统一放在这里处理,不用每个Action都重复写。

首先在你的API交互文件里配置:

// src/utils/api.js
import axios from 'axios';

// 创建Axios实例
const api = axios.create({
  baseURL: '/api',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
  }
});

// 请求拦截器:自动带上Passport的token
api.interceptors.request.use(config => {
  const token = localStorage.getItem('access_token');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
}, error => Promise.reject(error));

// 响应拦截器:统一处理所有错误
api.interceptors.response.use(
  response => response,
  error => {
    if (!error.response) {
      alert('网络连接异常,请检查网络');
      return Promise.reject(error);
    }

    const { status, data } = error.response;
    switch(status) {
      case 401:
        // 未授权:清除token并跳转登录页
        localStorage.removeItem('access_token');
        window.location.href = '/login';
        alert('登录已过期,请重新登录');
        break;
      case 422:
        // Laravel表单验证错误:提取第一个提示用户
        const firstError = Object.values(data.errors)[0][0];
        alert(firstError);
        break;
      case 500:
        alert('服务器内部错误,请稍后再试');
        break;
      default:
        alert(data.message || '请求失败');
    }

    // 抛出错误,让需要特殊处理的Action可以继续捕获
    return Promise.reject(error);
  }
);

export default api;

之后在Vuex Action里,只需要专注业务逻辑,除非有特殊需求才额外处理错误:

// src/store/modules/posts.js
import api from '@/utils/api';

const actions = {
  async fetchPosts({ commit }) {
    try {
      const res = await api.get('/posts');
      commit('SET_POSTS', res.data);
    } catch (error) {
      // 这里只处理这个Action独有的逻辑,比如标记请求失败状态
      commit('SET_REQUEST_FAILED', true);
    }
  },

  async createPost({ commit }, postData) {
    try {
      const res = await api.post('/posts', postData);
      commit('ADD_POST', res.data);
      alert('文章创建成功');
    } catch (error) {
      // 比如表单提交失败后滚动到页面顶部
      window.scrollTo(0, 0);
    }
  }
};

2. 封装API请求工具函数

如果不想用拦截器,也可以把请求逻辑封装成工具函数,把错误处理内置进去,让Vuex Action调用更简洁。

示例代码:

// src/utils/api.js
import axios from 'axios';

const api = axios.create({
  baseURL: '/api',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
  }
});

// 封装统一请求函数
async function request(method, url, data = null) {
  try {
    // 自动携带token
    const token = localStorage.getItem('access_token');
    if (token) {
      api.defaults.headers.common['Authorization'] = `Bearer ${token}`;
    }

    const res = await api[method](url, data);
    return res.data;
  } catch (error) {
    // 错误处理逻辑和拦截器一致
    if (!error.response) {
      alert('网络异常');
      throw error;
    }

    const { status, data } = error.response;
    switch(status) {
      case 401:
        localStorage.removeItem('access_token');
        window.location.href = '/login';
        break;
      case 422:
        alert(Object.values(data.errors)[0][0]);
        break;
      default:
        alert(data.message || '请求失败');
    }
    throw error;
  }
}

// 导出常用请求方法
export const get = url => request('get', url);
export const post = (url, data) => request('post', url, data);
export const put = (url, data) => request('put', url, data);
export const del = url => request('delete', url);

Vuex Action里的调用方式:

// src/store/modules/posts.js
import { get, post } from '@/utils/api';

const actions = {
  async fetchPosts({ commit }) {
    try {
      const posts = await get('/posts');
      commit('SET_POSTS', posts);
    } catch (error) {
      // 特殊处理逻辑
      console.error('获取文章失败:', error);
    }
  }
};

3. Vuex全局错误状态管理

如果想把错误状态统一管理,可以创建一个专门的Vuex模块来处理全局错误,结合Axios拦截器一起使用。

首先创建error模块:

// src/store/modules/error.js
const state = {
  isError: false,
  message: ''
};

const mutations = {
  SET_ERROR(state, message) {
    state.isError = true;
    state.message = message;
  },
  CLEAR_ERROR(state) {
    state.isError = false;
    state.message = '';
  }
};

const actions = {
  setError({ commit }, message) {
    commit('SET_ERROR', message);
    alert(message);
    // 3秒后自动清除错误状态
    setTimeout(() => commit('CLEAR_ERROR'), 3000);
  }
};

export default {
  namespaced: true,
  state,
  mutations,
  actions
};

然后在Axios拦截器里调用这个模块的Action:

// src/utils/api.js
import store from '@/store';

// 响应拦截器
api.interceptors.response.use(
  response => response,
  error => {
    let message = '请求失败';
    if (error.response) {
      const { status, data } = error.response;
      switch(status) {
        case 401:
          localStorage.removeItem('access_token');
          window.location.href = '/login';
          message = '登录已过期';
          break;
        case 422:
          message = Object.values(data.errors)[0][0];
          break;
        case 500:
          message = '服务器内部错误';
          break;
        default:
          message = data.message || message;
      }
    } else {
      message = '网络连接异常';
    }
    // 调用全局错误Action
    store.dispatch('error/setError', message);
    return Promise.reject(error);
  }
);

这种方式下,Vuex Action里完全不用处理错误提示,只需要关注业务逻辑即可。


内容的提问来源于stack exchange,提问作者PamanBeruang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 09:19:30