【Vue3进阶】- Axios 封装

774 阅读2分钟

在项目中一般会使用 axios - 基于 Promise 的网络请求库 来进行网络请求。 将 axios 进行适当的封装,在使用上可以事半功倍。

安装axios

npm install axios

基本使用

导入 axios 后就可以直接进行网络 api 请求,不过为了方便维护,处理跨域等问题会封装后再使用。

🎞️视频:Axios 封装用法

promise用法

import axios from "axios";

// get请求
axios.get("http://192.168.1.90:4000/api/login/sms?tel=13333333333")
import axios from "axios";

// get请求
axios
    .get("http://192.168.1.90:4000/api/login/sms?tel=13333333333")
    .then((res) => {
        // 处理成功情况
        console.log(res)
    })
    .catch(function (err) {
        // 处理错误情况
        console.log(err)
    })
    .finally(function () {
        // 总是会执行
    })


// post请求
axios
    .post("http://192.168.1.90:4000/api/login", {
        tel: 13333333333,
        code: 1234
    })
    .then(res => {
        console.log(res.data)
    })

async/await用法

import axios from "axios";

async function getSms() {
    try {
        const res = await axios.get("http://192.168.1.90:4000/api/login/sms?tel=13333333333")
        console.log(res);
    } catch (err) {
        console.error(err);
    }
}

创建实例


// 创建axios实例
let baseURL= ""
if (import.meta.env.DEV) { // 开发环境
  baseURL= "http://192.168.1.90:4000"
} else { // 生产环境
  baseURL= "http://xxx.com"
}

const service = axios.create({

    // 配置URL公共部分,如果要解决开发环境跨域问题这里不用配,在vite.config.json中配置
    baseURL: baseURL,

    // 设置请求超时时间单位毫秒
    timeout: 15000,

    // 设置请求头
    headers: {'X-Custom-Header': 'foobar'}

})

请求拦截器

axios 的请求拦截器,允许你在发出 HTTP 请求之前,==对请求进行预处理或修改==。 一般可以进行:

  1. 统一处理请求头:如在请求头中添加 token 或者其他信息。
  2. 请求参数统一格式化:如对查询参数进行额外的校验或格式化。
  3. 错误处理。

service.interceptors.request.use(
    (config) => {
        // 在这里可以对所有请求进行预处理,比如往请求头中添加token

        const token = localStorage.getItem('authToken');
        if (token) {
            config.headers['Authorization'] = `Bearer ${token}`;
        }

        // 如果一切正常,则必须返回config对象或者Promise.resolve(config)
        return config
    },
    (error) => {
        // 对请求错误做些什么
        // 返回Promise.reject(error),这样会触发后续的错误处理器
        Promise.reject(error)
    },
)

响应拦截器

axios 的响应拦截器会在接收到 HTTP 响应之后、调用者实际拿到响应结果之前介入处理。 一般可以进行:

  1. 统一处理响应结果:如将后端返回的数据结构标准化,或者对某些特定的状态码进行统一处理。
  2. 错误处理:针对非成功状态码(如 401、403、500 等)进行特殊处理,如用户未登录时重定向到登录页面、显示全局错误提示等。
  3. 数据缓存策略,对于某些特定类型的请求结果进行缓存,减少不必要的重复请求。

service.interceptors.response.use(
    (res) => {
        let data = res.data
        if (data.code !== 0) {
            Toast.error(data.msg)
            return Promise.reject(data)
        }

        return data // (相录于返回的 res 被自动 剥掉一层,变成 data 字段)
    },
    (error) => {
        if (error?.request?.status === 401 && location.pathname !== "/login") {
            // 当用户登录超时时,清空登录状态
            const store = useUsersStore()
            store.user = {}
            // 跳转到登录页
            if (error.config.url !== "/api/user/info") {
                sessionStorage.setItem("LOGIN_REDIRECT", location.hash.substr(1))
                router.replace("/login")
            }
        }
        return Promise.reject(error)
    },
)

最终代码

import axios from "axios"
import {Toast} from "@/until/toast"
import {useUsersStore} from "@/store/user"
import router from "@/router"

axios.defaults.headers["Content-Type"] = "application/json;charset=utf-8"
// 创建axios实例
const service = axios.create({
    // axios中请求配置有baseURL选项,表示请求URL公共部分
    // baseURL: 'http://localhost:4001',
    // 超时
    timeout: 15000,
})

// request拦截器
service.interceptors.request.use(
    (config) => {
        // 在这里可以对所有请求进行预处理,比如往请求头中添加token

        const token = localStorage.getItem('authToken');
        if (token) {
            config.headers['Authorization'] = `Bearer ${token}`;
        }

        // 如果一切正常,则必须返回config对象或者Promise.resolve(config)
        return config
    },
    (error) => {
        // 对请求错误做些什么
        // 返回Promise.reject(error),这样会触发后续的错误处理器
        Promise.reject(error)
    },
)

// 响应拦截器
service.interceptors.response.use(
    (res) => {
        let data = res.data
        if (data.code !== 0) {
            Toast.error(data.msg)
            return Promise.reject(data)
        }

        return data // (相录于返回的 res 被自动 剥掉一层,变成 data 字段)
    },
    (error) => {
        if (error?.request?.status === 401 && location.pathname !== "/login") {
            // 当用户登录超时时,清空登录状态
            const store = useUsersStore()
            store.user = {}
            // 跳转到登录页
            if (error.config.url !== "/api/user/info") {
                sessionStorage.setItem("LOGIN_REDIRECT", location.hash.substr(1))
                router.replace("/login")
            }
        }
        return Promise.reject(error)
    },
)

export default service

在项目中使用

在 src 下创建 api 目录,目录下创建相应模块的 js 文件 ( login.js、user.js... ),并且创建的 api 方法以 Api 结尾,这样方便与普通方法区分。 如果需要修改 api 路径,或者参数需要统一调整就可以在这里进行处理。

// /src/api/login.js

import request from "@/until/request"

// 发送登录验证码
export function sendSmsApi(tel) {
    // 这里的url不要写全从/api开始即可,方便配置环境切换/跨域
    return request.get("/api/login/sms?tel=" + tel)
}

// ... 其它api

直接导入需要使用的 api 方法 ( sendSmsApi ) 进行使用

// /src/views/login.vue

<script setup>
import {ref} from "vue"
import {sendSmsApi} from "@/api/login"

const tel = ref(null)

// 发送验证码
function sendSmsCode() {
  sendSmsApi(tel.value)
      .then((res) => {
        console.log(res.msg)
      })
}


</script>