不要过度封装!封装一个最简单的Axios! - 掘金 (juejin.cn)
1 初始化 axios 实例
通过 create 方法我们得到了一个 axios 的实例,该实例上有很多方法,比如拦截器等等。我们创建实例的时候可以配置一些基础设置,比如基础请求地址,请求超时等等。
// 创建 axios 请求实例
const serviceAxios = axios.create({baseURL: "", // 基础请求地址timeout: 10000, // 请求超时设置withCredentials: false, // 跨域请求是否需要携带 cookie
});
2 设置请求拦截
我们在发送请求的时候可能需要携带一些信息在请求头上,比如 token 等,所以说我们就需要将请求拦截下来,处理一些我们的业务逻辑。
// 创建请求拦截
serviceAxios.interceptors.request.use((config) => {// 如果开启 token 认证if (serverConfig.useTokenAuthorization) {config.headers["Authorization"] = localStorage.getItem("token"); // 请求头携带 token}// 设置请求头if(!config.headers["content-type"]) { // 如果没有设置请求头if(config.method === 'post') {config.headers["content-type"] = "application/x-www-form-urlencoded"; // post 请求config.data = qs.stringify(config.data); // 序列化,比如表单数据} else {config.headers["content-type"] = "application/json"; // 默认类型}}console.log("请求配置", config);return config;},(error) => {Promise.reject(error);}
);
3 设置响应拦截
axios 请求的返回结果里面包含了很多东西,我们的业务层面通常只需要后端返回的数据即可,所以我们需要设置相应拦截,在响应结果返回给业务层之前做一些操作。
// 创建响应拦截
serviceAxios.interceptors.response.use((res) => {let data = res.data;// 处理自己的业务逻辑,比如判断 token 是否过期等等// 代码块return data;},(error) => {let message = "";if (error && error.response) {switch (error.response.status) {case 302:message = "接口重定向了!";break;case 400:message = "参数不正确!";break;case 401:message = "您未登录,或者登录已经超时,请先登录!";break;case 403:message = "您没有权限操作!";break;case 404:message = `请求地址出错: ${error.response.config.url}`;break;case 408:message = "请求超时!";break;case 409:message = "系统已存在相同数据!";break;case 500:message = "服务器内部错误!";break;case 501:message = "服务未实现!";break;case 502:message = "网关错误!";break;case 503:message = "服务不可用!";break;case 504:message = "服务暂时无法访问,请稍后再试!";break;case 505:message = "HTTP 版本不受支持!";break;default:message = "异常问题,请联系管理员!";break;}}return Promise.reject(message);}
);
4 vue完整示例
在 src 下面新建 http 文件夹,用来存储关于 axios 请求的一些文件,然后在 http 文件夹下新建 index.js 文件,用于封装我们的 axios,然后在新建 config 文件夹,主要用来创建配置文件,最后新建一个 api 文件夹,用于集中管理我们的接口。
index.js 代码:
import axios from "axios";
import serverConfig from "./config";
import qs from "qs";// 创建 axios 请求实例
const serviceAxios = axios.create({baseURL: serverConfig.baseURL, // 基础请求地址timeout: 10000, // 请求超时设置withCredentials: false, // 跨域请求是否需要携带 cookie
});// 创建请求拦截
serviceAxios.interceptors.request.use((config) => {// 如果开启 token 认证if (serverConfig.useTokenAuthorization) {config.headers["Authorization"] = localStorage.getItem("token"); // 请求头携带 token}// 设置请求头if(!config.headers["content-type"]) { // 如果没有设置请求头if(config.method === 'post') {config.headers["content-type"] = "application/x-www-form-urlencoded"; // post 请求config.data = qs.stringify(config.data); // 序列化,比如表单数据} else {config.headers["content-type"] = "application/json"; // 默认类型}}console.log("请求配置", config);return config;},(error) => {Promise.reject(error);}
);// 创建响应拦截
serviceAxios.interceptors.response.use((res) => {let data = res.data;// 处理自己的业务逻辑,比如判断 token 是否过期等等// 代码块return data;},(error) => {let message = "";if (error && error.response) {switch (error.response.status) {case 302:message = "接口重定向了!";break;case 400:message = "参数不正确!";break;case 401:message = "您未登录,或者登录已经超时,请先登录!";break;case 403:message = "您没有权限操作!";break;case 404:message = `请求地址出错: ${error.response.config.url}`;break;case 408:message = "请求超时!";break;case 409:message = "系统已存在相同数据!";break;case 500:message = "服务器内部错误!";break;case 501:message = "服务未实现!";break;case 502:message = "网关错误!";break;case 503:message = "服务不可用!";break;case 504:message = "服务暂时无法访问,请稍后再试!";break;case 505:message = "HTTP 版本不受支持!";break;default:message = "异常问题,请联系管理员!";break;}}return Promise.reject(message);}
);
export default serviceAxios;
config/index.js 代码:
const serverConfig = {baseURL: "https://smallpig.site", // 请求基础地址,可根据环境自定义useTokenAuthorization: true, // 是否开启 token 认证
};
export default serverConfig;
api/user.js 接口调用示例代码:
import serviceAxios from "../index";export const getUserInfo = (params) => {return serviceAxios({url: "/api/website/queryMenuWebsite",method: "post",params,});
};
export const login = (data) => {return serviceAxios({url: "/api/user/login",method: "post",data,});
};
注意:get 请求需要传 params,post 请求需要传 data。
Vue 文件中调用示例:
import { login } from "@/http/api/user"
async loginAsync() {let params = {email: "123",password: "12321"}let data = await login(params);console.log(data);
}
5 下面是我项目中用到的配置~~~
const serviceAxios = axios.create({baseURL: "", // 基础请求地址 // 如 baseURL: baseUrl.apiBaseUrl, url = base url + request urltimeout: 10000, // 请求超时设置withCredentials: false, // 跨域请求是否需要携带 cookie
});// 添加请求拦截器
service.interceptors.request.use(function (config) {// 判断是否存在token,如果存在的话,则每个http header都加上tokenlet appToken = store.state.app.appTokenif (appToken) {config.headers['AppToken'] = appToken} else {config.headers['AppToken'] = window.localStorage.getItem('AppToken')}return config},function (error) {// 对请求错误做些什么return Promise.reject(error)}
)
// 添加响应拦截器
service.interceptors.response.use(function (response) {let contentType = response.headers['content-type']if (typeof contentType != 'undefined' && contentType.includes('application/octet-stream')) {return response.data}let { code, message, content } = response.dataswitch (code) {case 500000:Toast({ message: message, forbidClick: true })return Promise.reject(content)//登录已过期case 100003:Toast({ message: message, forbidClick: true })toLogin()return Promise.reject(content)//未登录case 100004:Toast({ message: message, forbidClick: true })toLogin()return Promise.reject(content)//未绑定银行卡case 100005:Toast({ message: message, forbidClick: true })router.replace({ path: '/notice' })return Promise.reject(content)//未实名认证case 100006:Toast({ message: message, forbidClick: true })router.replace({ path: '/notice' })return Promise.reject(content)default:return Promise.resolve(content)}},function (error) {return Promise.reject(error)}
)