Vue+Laravel多文件API调用:Axios异常返回处理与代码结构优化
问题解决与代码优化方案
一、解决Axios非2XX状态码错误无法传递到组件的问题
Axios默认会把非2XX状态码的响应抛出异常,你需要在Axios实例中添加响应拦截器,统一处理错误,把后端返回的错误信息正常传递给调用方。
1. 配置Axios拦截器(核心API配置文件)
import axios from 'axios' // 创建Axios实例 const apiClient = axios.create({ baseURL: '/api', // Laravel后端API前缀 headers: { 'Content-Type': 'application/json', }, }) // 响应拦截器:处理错误响应 apiClient.interceptors.response.use( response => response, // 正常响应直接返回 error => { // 提取后端返回的错误信息,适配Laravel的返回格式 const errorMessage = error.response?.data?.message || '请求失败,请稍后重试' // 包装错误后抛出,让组件能捕获到具体信息 return Promise.reject(new Error(errorMessage)) } ) export default apiClient
2. 模型API文件(如models/User.js)
import apiClient from '../api.js' export default { login(credentials) { return apiClient.post('/login', credentials) }, // 其他用户相关API... }
3. 在Login.vue组件中处理错误
<template> <div> <input v-model="form.email" type="email" placeholder="邮箱"> <input v-model="form.password" type="password" placeholder="密码"> <button @click="handleLogin">登录</button> <p v-if="errorMsg" class="text-red-500">{{ errorMsg }}</p> </div> </template> <script> import UserApi from '@/models/User.js' export default { data() { return { form: { email: '', password: '' }, errorMsg: '' } }, methods: { async handleLogin() { this.errorMsg = '' try { const response = await UserApi.login(this.form) // 登录成功逻辑:存token、跳转首页等 console.log('登录成功', response.data) } catch (err) { // 捕获拦截器传递的错误信息并展示 this.errorMsg = err.message } } } } </script>
二、更合理的代码组织方案
推荐按API核心配置、拦截器、模型API拆分目录,结构清晰、职责单一,便于后续维护扩展:
目录结构
src/ ├── api/ │ ├── index.js # Axios实例创建、拦截器挂载 │ ├── interceptors/ │ │ ├── request.js # 请求拦截器(如添加token) │ │ └── response.js # 响应拦截器(统一错误处理) │ └── models/ │ ├── User.js # 用户模块API │ ├── Post.js # 文章模块API │ └── ... # 其他模型API └── components/ └── Login.vue # 登录组件
各文件职责说明
- api/index.js:创建Axios实例并挂载拦截器
import axios from 'axios' import requestInterceptor from './interceptors/request' import responseInterceptor from './interceptors/response' const apiClient = axios.create({ baseURL: process.env.VUE_APP_API_BASE_URL || '/api', headers: { 'Content-Type': 'application/json', }, }) // 挂载请求/响应拦截器 apiClient.interceptors.request.use(requestInterceptor) apiClient.interceptors.response.use( response => response, responseInterceptor ) export default apiClient
- api/interceptors/request.js:处理请求前置逻辑
export default function requestInterceptor(config) { // 从localStorage获取token,添加到请求头 const token = localStorage.getItem('auth_token') if (token) { config.headers.Authorization = `Bearer ${token}` } return config }
- api/interceptors/response.js:精细化处理不同错误场景
export default function responseInterceptor(error) { // 网络异常处理 if (!error.response) { return Promise.reject(new Error('网络异常,请检查网络连接')) } const { status, data } = error.response let errorMsg = '请求失败,请稍后重试' // 适配Laravel常见状态码的错误提示 switch (status) { case 401: errorMsg = data.message || '登录已过期,请重新登录' // 可在此添加跳转登录页的逻辑 break case 422: // 提取表单验证的第一个错误信息 errorMsg = Object.values(data.errors)[0][0] break case 403: errorMsg = data.message || '权限不足,无法访问' break default: errorMsg = data.message || errorMsg } return Promise.reject(new Error(errorMsg)) }
- api/models/User.js:只封装用户相关API
import apiClient from '../index.js' export const UserApi = { login(credentials) { return apiClient.post('/login', credentials) }, logout() { return apiClient.post('/logout') }, getUserInfo() { return apiClient.get('/user') } } export default UserApi
这种拆分方式让每个模块职责明确,拦截器逻辑与API调用分离,后续新增模型或修改拦截规则时不会互相干扰,更符合模块化开发的思路。
内容的提问来源于stack exchange,提问作者iamsubingyawali
相关产品推荐
相关产品推荐

