小白系列Vite-Vue3-TypeScript:007-配置axios并封装api

上一篇我们介绍了Vite+Vue3+TypeScript项目中Element Plus的安装和配置,本篇我们来介绍一下如何配置axios并封装api。

axios是一个基于promise的HTTP库,可以用在浏览器和node.js中,其最大的亮点就是支持了ES6里的Promise Api。废话不多说,直接撸起来......

安装axios

有时候可能需要对请求或者相应参数进行解析或者格式转换,所以除了axios库之外,一般我们还会安装qs(一个流行的查询参数序列化和解析库),qs可以将一个普通的object序列化成一个查询字符串,或者反过来将一个查询字符串解析成一个object,而且支持复杂的嵌套。

//安装axios
npm i axios -S

//安装qs
npm i qs -S

配置vite环境变量(区分开发和生产环境)

创建环境文件

项目根目录下创建文件 .env.dev(开发测试环境)和文件 .env.prod(生产环境)

.env.dev文件代码如下

#(.env.dev 测试/开发环境变量配置)
VITE_ENV = development

# base api

# 初始地址, 注意端口号要与vite.config.ts的server部分一致
VITE_SOURCE_URL = http://localhost:8088

# 基础域名
VITE_BASE_API = http://localhost:8088

# 服务地址
VITE_SERVE_ADD = /api

.env.prod文件代码如下

#(.env.prod 生产环境变量配置)
VITE_ENV = development

# base api

# 初始地址, 注意端口号要与vite.config.ts的server部分一致
VITE_SOURCE_URL = http://192.168.5.106:8088

# 基础域名
VITE_BASE_API = http://192.168.5.106:8088

# 服务地址
VITE_SERVE_ADD = /api

更新指令

修改package.js的脚本命令内容

"scripts": {
  "dev": "vite --mode dev",
  "prod": "vite --mode prod",
  "build": "vue-tsc && vite build --mode prod",
  "preview": "vite preview"
},

这样配置完成后,运行npm run dev或npm run prod或build时会把自定义的环境变量载入进去,避免了每次打包和开发都要临时修改变量的尴尬。

创建config.ts配置文件

上面我们已经创建好了环境变量,在src目录下新建config.ts文件来接收环境变量以及后面可能出现的公用配置。

/** 环境变量 */
const ENV = import.meta.env;  // vite是以这种方式获取环境变量

/** 基础域名 */
export const SOURCE_URL = ENV.VITE_SOURCE_URL;
export const BASE_URL = ENV.VITE_BASE_API;

/** 基础服务地址 */
export const URL = BASE_URL + '/api';

/** 超时时间 */
export const TIMEOUT = 6000;

这样在后面创建axios实例和封装api的时候,就可以直接通过config.ts文件来读取配置了。

创建axios实例文件

在项目src/utils目录下(没有的话创建即可)新建request.ts文件,这个文件就是我们要书写axios的api封装。封装过程中用到了Message组件,刚好上一篇我们已经介绍了安装及配置ElementPlus的过程。同时引入token管理。

导入所需依赖

import axios, { AxiosRequestConfig } from 'axios'
import qs from 'qs'
import { setLocalStorage, getLocalStorage } from './localstorage'
import { BASE_URL, TIMEOUT, SOURCE_URL } from "@/config";

导入qs的时候一般情况下,编辑器会报错“无法找到模块“qs”的声明文件

因为TypeScript中s不能直接这样引入js类型库,解决方法:在src目录下新建一个globe.d.ts,添加如下代码即可

declare module "qs"

创建实例

const instance = axios.create({
    baseURL: BASE_URL,
    timeout: TIMEOUT,
    headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
    }
})

配置请求拦截器

// http request 请求拦截器
instance.interceptors.request.use(
    config => {
        config.headers.AcceptLanguage = getLocalStorage("locale");
        if (localStorage.myToken) {
            config.headers.Authorization = getLocalStorage("myToken");
        }
        return config
    },
    err => {
        return Promise.reject(err)
    }
)

配置响应拦截器

// http response 响应拦截器
instance.interceptors.response.use(
    response => {
        return handleData(response.data)
    },
    error => {
        const errData = error.response.data
        if (errData.status === 500) {
            setLocalStorage('myToken');
            window.location.href = sourceUrl;
        }
        let err = errData.message;
        if (err != '' && err != null && err != undefined) {
            ElMessage({
                type: 'error',
                message: errData.message
            })
            return Promise.reject(errData)
        } else {
            ElMessage({
                type: 'error',
                message: 'HTTP:服务器遇到错误,请求失败。'
            })
        }
    }
)

封装API

// API封装
const get = async (url: string) => {
    /**
     ......
     可以在这里自定义封装处理方法
     ......
     */
    try {
        return await instance
            .get(url)
    } catch (error) {
        return handleError(error)
    }
}

完整代码

request.ts

import axios, { AxiosRequestConfig } from 'axios'
import qs from 'qs'
import { setLocalStorage, getLocalStorage } from './localstorage'
import { BASE_URL, TIMEOUT, SOURCE_URL } from "@/config";
const instance = axios.create({
    baseURL: BASE_URL,
    timeout: TIMEOUT,
    headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
    }
})
// http request 请求拦截器
instance.interceptors.request.use(
    config => {
        config.headers.AcceptLanguage = getLocalStorage("locale");
        if (localStorage.myToken) {
            config.headers.Authorization = getLocalStorage("myToken");
        }
        return config
    },
    err => {
        return Promise.reject(err)
    }
)
// http response 响应拦截器
instance.interceptors.response.use(
    response => {
        return handleData(response.data)
    },
    error => {
        const errData = error.response.data
        if (errData.status === 500) {
            setLocalStorage('myToken');
            window.location.href = SOURCE_URL;
        }
        let err = errData.message;
        if (err != '' && err != null && err != undefined) {
            ElMessage({
                type: 'error',
                message: errData.message
            })
            return Promise.reject(errData)
        } else {
            ElMessage({
                type: 'error',
                message: 'HTTP:服务器遇到错误,请求失败。'
            })
        }
    }
)

// API封装
const get = async (url: string) => {
    /**
     ......
     可以在这里自定义封装处理方法
     ......
     */
    try {
        return await instance
            .get(url)
    } catch (error) {
        return handleError(error)
    }
}
const post = async (url: string, data?: any, config?: AxiosRequestConfig<any> | undefined) => {
    /**
    ......
    可以在这里自定义封装处理方法
    ......
    */
    try {
        return await instance
            .post(url, data, config)
    } catch (error) {
        return handleError(error)
    }
}
const deleteFn = async (url: string, config?: AxiosRequestConfig<any> | undefined) => {
    /**
    ......
    可以在这里自定义封装处理方法
    ......
    */
    try {
        return await instance
            .delete(url, config)
    } catch (error) {
        return handleError(error)
    }
}
const postJSON = async (url: string, data?: any, config?: AxiosRequestConfig<any> | undefined) => {
    /**
    ......
    可以在这里自定义封装处理方法
    ......
    */
    data = qs.stringify(data);
    try {
        return await instance
            .post(url, data, config)
    } catch (error) {
        return handleError(error)
    }
}
const patchFn = async (url: string, data?: any, config?: AxiosRequestConfig<any> | undefined) => {
    /**
    ......
    可以在这里自定义封装处理方法
    ......
    */
    try {
        return await instance
            .patch(url, data, config)
    } catch (error) {
        return handleError(error)
    }
}
// 对请求返回的错误进行自处理
function handleError(error: any) {
    return error
}
// 对响应的数据进行自处理
function handleData(data: any) {
    return data
}
export default {
    get: get,
    post: post,
    postJSON: postJSON,
    delete: deleteFn,
    patch: patchFn
}

localstorage.ts


export const setLocalStorage = (key: string, value?: string, hours?: number) => {
    value = JSON.stringify(value);
    // 设置过期原则
    if (!value) {
        localStorage.removeItem(key)
    } else {
        let Hours = hours || 24; // 以小时为单位,默认24小时
        let exp = new Date();
        localStorage[key] = JSON.stringify({
            value,
            expires: exp.getTime() + Hours * 1000 * 60 * 60,//失效时间
        })
    }
}
export const getLocalStorage = (key: string) => {
    try {
        let ls = JSON.parse(localStorage[key]);
        if (!ls || ls.expires < Date.now()) {
            return ''
        } else {
            return JSON.parse(ls.value)
        }
    } catch (e) {
        // 兼容其他localstorage
        return localStorage[key]
    }
}

config.ts

/** 环境变量 */
const ENV = import.meta.env;  // vite是以这种方式获取环境变量

/** 基础域名 */
export const SOURCE_URL = ENV.VITE_SOURCE_URL;
export const BASE_URL = ENV.VITE_BASE_API;

/** 基础服务地址 */
export const URL = BASE_URL + '/api';

/** 超时时间 */
export const TIMEOUT = 6000;

OK,这样基本就完成了axios的安装和api封装了!

我相信,每天学习一点点,收获成长亿点点!

猜你喜欢

转载自blog.csdn.net/qq_34205305/article/details/128937275