目录
- 一、安装axios
- 二、创建axios实例
- 三、请求拦截器
- 四、响应拦截器
- 五、 封装post、get等方法
- 调用方法
- 六、完整代码
- 七、总结
一、安装axios
Axios 中文文档 (https://www.axios-http.cn/)
使用安装命令,将axios安装到项目上,当前文章案例采用vite3+vue3+typescript项目
npm install axios
先来个文件目录结构吧
二、创建axios实例
// 配置新建一个 axios 实例
const service = axios.create({
baseURL: import.meta.env.MODE == 'development' ? '' : (import.meta.env.VITE_API_URL || ''),
timeout: 15000,
headers: { 'Content-Type': 'application/json' },
});
简单创建一个axios
实例,
baseURL
:请求接口的地址,一般在开发环境会配置代理,baseURL
可以为空,生产环境中不需要代理,可以直接写后端接口地址,这里使用了环境变量import.meta.env.VITE_API_URL
,当打包上线的时候,只需要更改.env
文件的VITE_API_URL
,不需要找到当前这个文件来修改,而且开发跟线上用的是不同地址时,也很方便,只需设置环境变量的地址就行了
补充一个环境变量的知识 vite.config.ts里面使用环境变量
三、请求拦截器
请求拦截器的作用是在请求发送前进行一些操作,例如在每个请求时携带上token,追加参数,对参数配合后端做加密处理等等
// 添加请求拦截器
// 添加请求拦截器
service.interceptors.request.use((config) => {
// 在发送请求之前做些什么
// 例如追加token
let token = sessionStorage.get('token');
if (token) { // token存放到请求头中
(config.headers as any).common['Authorization'] = token;
}
// post请求参数在 config.data里,get请求在config.params里面
let type: 'params' | 'data' = config.method == 'post' ? 'data' : 'params'
// 可以在里面追参数,例如添加一个时间戳time
// config[type] = {
// ...config[type],
// time: Date.now()
// }
return config;
}, (error) => {
// 对请求错误做些什么
return Promise.reject(error);
});
四、响应拦截器
响应拦截器的作用是在接收到响应后进行一些操作,例如在服务器返回登录状态失效,需要重新登录的时候,跳转到登录页。
// 添加响应拦截器
service.interceptors.response.use((response) => {
// 对响应数据做点什么
// 例如登录失效的操作
// const res = response.data;
// if (res.code && res.code == 403) {
// // `token` 过期或者账号已在别处登录
// sessionStorage.clear(); // 清除浏览器全部临时缓存
// window.location.href = '/'; // 去登录页
// ElMessageBox.alert('账号已过期,请重新登录', '提示', {})
// .then(() => { })
// .catch(() => { });
// return Promise.reject(service.interceptors.response);
// } else {
// return response.data;
// }
return response.data; // 这里返回 response.data,默认返回整个axios对象,后端返回的在response.data包起来了
}, (error) => {
// 对响应错误做点什么
// 根据相应的error数据去写提示
if (error.message.indexOf('timeout') != -1) {
ElMessage.error('网络超时');
} else if (error.message == 'Network Error') {
ElMessage.error('网络连接错误');
} else {
ElMessage.error(error.response.status + ',' + error.response.statusText);
// if (error.response.data) else ElMessage.error('接口路径找不到');
}
return Promise.reject(error);
});
这里用的时Element-plus
的提示组件,可以换成自己项目的提示组件
五、 封装post、get等方法
先与后端约定好返回的一个大致格式,如:code,msg,data等等
/**
* 跟后端约定返回的数据格式
*/
interface ResponseData<T> {
code: number; // 状态码,示例:- 200 : 成功
msg: string; // 返回文字描述,示例:- 提交成功
data: T; // 泛型数据,定义接口时传过来类型
}
简单封装一下接口,最后设置返回类型为Promise<ResponseData<T>>
/**
* @method post请求
* @param {string} url 请求接口路由地址
* @param {any} [data] 接口参数
* @param {any} [config] 请求头部配置信息
* @returns {Promise<ResponseData<T>>}
*/
const post = <T = any>(url: string, data?: any, config?: any): Promise<ResponseData<T>> => {
return service.post(url, data, { ...config })
}
/**
* @method get请求
* @param {string} url 请求接口路由地址
* @param {any} [data] 接口参数
* @param {any} [config] 请求头部配置信息
* @returns {Promise<ResponseData<T>>}
*/
const get = <T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<ResponseData<T>> => {
return service.get(url, {
params: data,
...config
})
}
/**
* @method del删除
* @param {string} url 请求接口路由地址
* @param {any} [data] 接口参数
* @param {any} [config] 请求头部配置信息
* @returns {Promise<ResponseData<T>>}
*/
const del = <T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<ResponseData<T>> => {
return service.delete(url, {
params: data,
...config
})
}
/**
* @method put请求
* @param {string} url 请求接口路由地址
* @param {any} [data] 接口参数
* @param {any} [config] 请求头部配置信息
* @returns {Promise<ResponseData<T>>}
*/
const put = <T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<ResponseData<T>> => {
return service.put(url, data, { ...config })
}
调用方法
登录接口/src/api/login.ts
import { post } from '@/utils/http/request';
/**
* 登录 - 请求参数
*/
interface LoginData {
user: string;
password: string;
}
/**
* 登录 - 接口响应数据
*/
interface LoginDataResponse {
token: string;
user_info: {
name: string;
role_id: string;
};
}
/**
* 登录api
* @method getCode 获取验证码
* @method signIn 登录
*/
export const LoginApi = {
signIn: (data: LoginData) => post<LoginDataResponse>("/api/admin_auth/login", data),
}
在login.vue文件里面调用
六、完整代码
import axios, { AxiosRequestConfig } from 'axios';
import { ElMessage, ElMessageBox } from 'element-plus';
// 配置新建一个 axios 实例
const service = axios.create({
baseURL: import.meta.env.MODE == 'development' ? '' : (import.meta.env.VITE_API_URL || ''),
timeout: 15000,
headers: { 'Content-Type': 'application/json' },
});
// 添加请求拦截器
service.interceptors.request.use((config) => {
// 在发送请求之前做些什么
// 例如追加token
let token = sessionStorage.get('token');
if (token) { // token存放到请求头中
(config.headers as any).common['Authorization'] = token;
}
// post请求参数在 config.data里,get请求在config.params里面
let type: 'params' | 'data' = config.method == 'post' ? 'data' : 'params'
// 可以在里面追参数,例如添加一个时间戳time
// config[type] = {
// ...config[type],
// time: Date.now()
// }
return config;
}, (error) => {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
service.interceptors.response.use((response) => {
// 对响应数据做点什么
// 例如登录失效的操作
// const res = response.data;
// if (res.code && res.code == 403) {
// // `token` 过期或者账号已在别处登录
// sessionStorage.clear(); // 清除浏览器全部临时缓存
// window.location.href = '/'; // 去登录页
// ElMessageBox.alert('账号已过期,请重新登录', '提示', {})
// .then(() => { })
// .catch(() => { });
// return Promise.reject(service.interceptors.response);
// } else {
// return response.data;
// }
return response.data; // 这里返回 response.data,默认返回整个axios对象,后端返回的在response.data包起来了
}, (error) => {
// 对响应错误做点什么
if (error.message.indexOf('timeout') != -1) {
ElMessage.error('网络超时');
} else if (error.message == 'Network Error') {
ElMessage.error('网络连接错误');
} else {
ElMessage.error(error.response.status + ',' + error.response.statusText);
// if (error.response.data) else ElMessage.error('接口路径找不到');
}
return Promise.reject(error);
});
/**
* 跟后端约定返回的数据格式
*/
interface ResponseData<T> {
code: number; // 状态码,示例:- 200 : 成功
msg: string; // 返回文字描述,示例:- 提交成功
data: T; // 泛型数据,定义接口时传过来类型
}
/*** 方法封装 **********************************/
/**
* @method post请求
* @param {string} url 请求接口路由地址
* @param {any} [data] 接口参数
* @param {any} [config] 请求头部配置信息
* @returns {Promise<ResponseData<T>>}
*/
const post = <T = any>(url: string, data?: any, config?: any): Promise<ResponseData<T>> => {
return service.post(url, data, { ...config })
}
/**
* @method get请求
* @param {string} url 请求接口路由地址
* @param {any} [data] 接口参数
* @param {any} [config] 请求头部配置信息
* @returns {Promise<ResponseData<T>>}
*/
const get = <T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<ResponseData<T>> => {
return service.get(url, {
params: data,
...config
})
}
/**
* @method del删除
* @param {string} url 请求接口路由地址
* @param {any} [data] 接口参数
* @param {any} [config] 请求头部配置信息
* @returns {Promise<ResponseData<T>>}
*/
const del = <T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<ResponseData<T>> => {
return service.delete(url, {
params: data,
...config
})
}
/**
* @method put请求
* @param {string} url 请求接口路由地址
* @param {any} [data] 接口参数
* @param {any} [config] 请求头部配置信息
* @returns {Promise<ResponseData<T>>}
*/
const put = <T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<ResponseData<T>> => {
return service.put(url, data, { ...config })
}
// 导出 axios 实例
export { post, get, del, put, service as request }
// export default service;
七、总结
二次封装axios方法很多,文章也很多,关键是适合自己,符合项目需求才是最好的,有些东西还是需要根据业务需求来写的,不一定写的越多越好!