Vue 项目中封装 axios

在 Vue 项目中二次封装 axios,统一管理请求配置和拦截器

问题

在 Vue 项目中如何封装 axios,避免重复配置请求头、超时时间、错误处理等代码?

解答

为什么要封装

axios 的 API 很友好,可以直接使用。但随着项目规模增大,每次发起 HTTP 请求都要重复配置超时时间、请求头、环境地址、错误处理等,代码会变得冗余:

axios('http://localhost:3000/data', {
  method: 'GET',
  timeout: 1000,
  withCredentials: true,
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'xxx',
  },
  transformRequest: [function (data, headers) {
    return data;
  }],
})

通过二次封装可以统一管理这些配置,提高代码质量和维护性。

封装步骤

1. 设置接口请求前缀

根据环境变量区分开发、测试、生产环境:

if (process.env.NODE_ENV === 'development') {
  axios.defaults.baseURL = 'http://dev.xxx.com'
} else if (process.env.NODE_ENV === 'production') {
  axios.defaults.baseURL = 'http://prod.xxx.com'
}

本地开发时在 vue.config.js 配置代理:

devServer: {
  proxy: {
    '/proxyApi': {
      target: 'http://dev.xxx.com',
      changeOrigin: true,
      pathRewrite: {
        '/proxyApi': ''
      }
    }
  }
}

2. 设置请求头与超时时间

创建 axios 实例,配置通用请求头:

const service = axios.create({
  timeout: 30000,
  headers: {
    get: {
      'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
    },
    post: {
      'Content-Type': 'application/json;charset=utf-8'
    }
  }
})

3. 封装请求方法

封装 GET 和 POST 方法:

// GET 请求
export function httpGet({ url, params = {} }) {
  return new Promise((resolve, reject) => {
    axios.get(url, { params })
      .then((res) => {
        resolve(res.data)
      })
      .catch(err => {
        reject(err)
      })
  })
}

// POST 请求
export function httpPost({ url, data = {} }) {
  return new Promise((resolve, reject) => {
    axios.post(url, data)
      .then((res) => {
        resolve(res.data)
      })
      .catch(err => {
        reject(err)
      })
  })
}

4. 统一管理 API

api.js 中统一管理接口:

import { httpGet, httpPost } from './http'

export const getorglist = (params = {}) => httpGet({ 
  url: 'apps/api/org/list', 
  params 
})

页面中调用:

import { getorglist } from '@/assets/js/api'

getorglist({ id: 200 }).then(res => {
  console.log(res)
})

5. 请求拦截器

在请求发送前统一添加 token:

axios.interceptors.request.use(
  config => {
    const token = localStorage.getItem('token')
    if (token) {
      config.headers.Authorization = token
    }
    return config
  },
  error => {
    return Promise.reject(error)
  }
)

6. 响应拦截器

根据状态码统一处理响应:

axios.interceptors.response.use(
  response => {
    if (response.status === 200) {
      if (response.data.code === 511) {
        // 未授权处理
      } else if (response.data.code === 510) {
        // 未登录跳转登录页
      } else {
        return Promise.resolve(response)
      }
    }
    return Promise.reject(response)
  },
  error => {
    // 错误处理
    return Promise.reject(error)
  }
)

关键点

  • 根据环境变量设置不同的 baseURL,开发环境配置代理解决跨域
  • 创建 axios 实例统一配置超时时间和请求头
  • 封装 GET、POST 等方法,返回 Promise 便于调用
  • 使用请求拦截器统一添加 token 等认证信息
  • 使用响应拦截器统一处理状态码、错误和登录态