封装axios,使代码更简洁,也便于对请求和响应进行统一管理。
封装常用请求方法
定义axios的配置信息,用于在创建axios实例时传入,封装常用的get、put、post、delete接口方法。
- 在src\router\index.ts写入以下代码
import axios, {AxiosInstance,AxiosRequestConfig} from 'axios'
// 数据返回的接口
// 定义请求响应参数
interface Result<T> {
code: number;
msg: string;
data?: T;
}
const config = {
// 默认地址
baseURL: "http://localhost:8080",
// 设置超时时间
timeout: 3000,
}
class Request {
// 定义成员变量并指定类型
service: AxiosInstance;
public constructor(config: AxiosRequestConfig) {
// 实例化axios
this.service = axios.create(config);
}
// 常用方法封装
get<T>(url: string, params?: object): Promise<Result<T>> {
return this.service.get(url, {params});
}
post<T>(url: string, params?: object): Promise<Result<T>> {
return this.service.post(url, params);
}
put<T>(url: string, params?: object): Promise<Result<T>> {
return this.service.put(url, params);
}
delete<T>(url: string, params?: object): Promise<Result<T>> {
return this.service.delete(url, {params});
}
}
// 导出一个实例对象
export default new Request(config);
- 封装完毕后使用在src\api\loginRegister.ts,中使用封装好的方法
import request from '../utils/request'
export default {
test:()=>{
return request.get('user/getMessage');
},
}
- 在页面中使用src\api\loginRegister.ts中的方法
<template>
<div>
<el-button type="primary" size="default" @click="test">test</el-button>
</div>
</template>
<script setup lang="ts">
import lAndR from "../../api/loginRegister"
const test = ()=>{
lAndR.test().then((res)=>{
console.log("test",res);
})
}
</script>
<style lang="scss" scoped>
</style>
至此,axios常用方法的封装完成了。
请求拦截器
用于在发送请求前给请求头添加token
//请求拦截器
this.service.interceptors.request.use(
//这里的config声明为AxiosRequestConfig类型会报错,很奇怪
(config: any) => {
//将token从userStore取出放入请求头中
const token = userMsg.userToken || '';
config.headers.token = token;
return config;
},
(error: any) => {
// 请求报错
Promise.reject(error)
}
)
未添加token的请求头
添加token后的请求头
响应拦截器
响应拦截器,对token过期或失效进行处理;拦截全局错误信息
/**
* 响应拦截器
*/
this.service.interceptors.response.use(
(response: AxiosResponse) => {
const {data} = response; // 解构
if (data.code === 3010) {
// 3010登录信息失效码,清空token
userMsg.setToken('');
return Promise.reject(data);
}
// 全局错误信息拦截(防止下载文件得时候返回数据流,没有code,直接报错)
if (data.code && data.code !== 2000) {
ElMessage.error(data);
return Promise.reject(data)
}
//页面请求的返回结果
return data;
},
(error: AxiosError) => {
const {response} = error;
if (response) {
ElMessage.error('请求失败');
}
if (!window.navigator.onLine) {
ElMessage.error('网络连接失败');
});
}
}
)
需要注意是,添加响应拦截器后,在页面中请求的返回结果,是拦截器中解构后返回的data,因此数据的结构和之前的有所不同,比如res.data.data.role变成res.data.role。
同时因为因为对状态码的处理都在响应拦截器进行,所以在页面中请求时不需要额外对状态码进行判断处理,直接在then和catch中写请求成功或失败后的处理即可
例如,未添加响应拦截器前的登录请求
const toLogin = async() => {
//进行表单校验,返回promise
await formRef.value?.validate().then(()=>{
let user={
userName:form.name,
passward:form.password
}
lAndR.login(user).then((res)=>{
if(res.data.code === 2000){
userMsg.setToken(res.data.data.token);
ElMessage.success("登录成功");
router.replace("/");
}else{
ElMessage.error(res.data.msg);
clear();
}
console.log(res);
})
})
.catch((err)=>{
console.log(err[0]);
ElMessage.error('校验失败');
})
}
添加响应拦截器后的登录请求
const toLogin = async() => {
//进行表单校验,返回promise
await formRef.value?.validate().then(()=>{
let user={
userName:form.name,
passward:form.password
}
console.log("user",user);
lAndR.login(user).then((res:any)=>{
userMsg.setToken(res.data.token);
ElMessage.success("登录成功");
if(res.data.role == 1){
router.replace("/BackendHome");
}else{
router.replace("/");
}
console.log(res);
}).catch(()=>{
clear();
})
})
.catch(()=>{
ElMessage.error('校验失败');
})
}
至此axios常用请求封装和请求响应拦截器的设置就完成辣,完整代码如下
import axios, {AxiosInstance,AxiosRequestConfig,AxiosResponse,AxiosError} from 'axios'
import {userStore} from '../stores'
import { useRouter } from "vue-router";
import { ElMessage } from 'element-plus'
const userMsg = userStore();
const router = useRouter();
// 数据返回的接口
// 定义请求响应参数
interface Result<T> {
code: number;
msg: string;
data?: T;
}
const config = {
// 默认地址
baseURL: "http://localhost:8080",
// 设置超时时间
timeout: 3000,
// 跨域时候允许携带凭证
// withCredentials: true
}
class Request {
// 定义成员变量并指定类型
service: AxiosInstance;
public constructor(config: AxiosRequestConfig) {
// 实例化axios
this.service = axios.create(config);
/**请求拦截器
* 发起请求时添加token
*/
this.service.interceptors.request.use(
//这里的config声明为AxiosRequestConfig类型会报错,很奇怪
(config: any) => {
//将token从userStore取出放入请求头中
const token = userMsg.userToken || '';
config.headers.token = token;
return config;
},
(error: AxiosError) => {
// 请求报错
Promise.reject(error)
}
)
/**
* 响应拦截器
* 1.对token过期或失效进行处理
* 2.拦截全局错误信息
*/
this.service.interceptors.response.use(
(response: AxiosResponse) => {
const {data} = response; // 解构
if (data.code === 3010) {
// 3010登录信息失效码,应跳转到登录页面,并清空token
userMsg.setToken('');
return Promise.reject(data);
}
// 全局错误信息拦截(防止下载文件得时候返回数据流,没有code,直接报错)
if (data.code && data.code !== 2000) {
console.log(data.code !== 2000)
ElMessage.error(data.msg);
return Promise.reject(data)
}
return data;
},
(error: AxiosError) => {
const {response} = error;
if (response) {
ElMessage.error('请求失败');
}
if (!window.navigator.onLine) {
ElMessage.error('网络连接失败');
});
}
}
)
}
// 常用方法封装
get<T>(url: string, params?: object): Promise<Result<T>> {
return this.service.get(url, {params});
}
post<T>(url: string, params?: object): Promise<Result<T>> {
return this.service.post(url, params);
}
put<T>(url: string, params?: object): Promise<Result<T>> {
return this.service.put(url, params);
}
delete<T>(url: string, params?: object): Promise<Result<T>> {
return this.service.delete(url, {params});
}
}
// 导出一个实例对象
export default new Request(config);