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
相关产品推荐
相关产品推荐

