上一篇我们介绍了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封装了!
我相信,每天学习一点点,收获成长亿点点!