Vue3+Axios网络请求封装(转)
转自:原文链接:https://blog.csdn.net/weixin_43295498/article/details/130939488
代码说明
代码主要分为以下几个部分:
import导入模块。在这个代码段中,我们导入了axios和element-plus两个模块,并对其进行了解构。
定义两个接口,CustomOptions和LoadingOptions。分别用于定义自定义配置和加载选项的接口,方便在调用Axios方法时传递配置和选项。
定义了一个Map对象pendingMap,用于储存每个请求的唯一回调函数。
定义了一个LoadingInstance对象,用于储存loading实例和计数器。
getTokenAUTH()方法用于获取token,该方法可以根据实际情况编写。
Axios()方法是Axios库的核心方法,主要进行了请求和响应拦截,并处理了请求重复、超时和错误状态码等异常情况。
httpErrorStatusHandle()方法用于处理错误状态码。
closeLoading()方法用于关闭loading层实例。
addPending()方法用于储存每个请求的唯一回调函数,以此为标识。
removePending()方法用于删除重复请求。
getPendingKey()方法用于生成每个请求的唯一key。
完整代码(中间件/网络请求拦截器-Typescript版本)
import axios, {AxiosRequestConfig, AxiosError, AxiosResponse, CancelToken} from 'axios'; import {ElLoading, ElMessage} from 'element-plus'; interface CustomOptions { repeat_request_cancel?: boolean; loading?: boolean; restore_data_format?: boolean; error_message_show?: boolean; code_message_show?: boolean; } interface LoadingOptions { fullscreen?: boolean; text?: string; customClass?: string; spinner?: string; background?: string; } const pendingMap: Map<string, CancelToken> = new Map(); interface LoadingInstance { _target: any; _count: number; } const LoadingInstance: LoadingInstance = { _target: null, _count: 0, }; function getTokenAUTH(): string { return ""; } function Axios( axiosConfig: AxiosRequestConfig, customOptions: CustomOptions = {}, loadingOptions: LoadingOptions = {} ) { const service = axios.create({ baseURL: process.env.VUE_APP_BASE_API, timeout: 1000 * 60, responseType: 'json', }); // 自定义配置 const custom_options = Object.assign( { repeat_request_cancel: true, loading: false, restore_data_format: true, error_message_show: true, code_message_show: false, }, customOptions ); // 请求拦截 service.interceptors.request.use( (config: any) => { removePending(config); custom_options.repeat_request_cancel && addPending(config); // 创建loading实例 if (custom_options.loading) { LoadingInstance._count++; if (LoadingInstance._count === 1) { LoadingInstance._target = ElLoading.service(loadingOptions); } } // 自动携带token if (getTokenAUTH() && typeof window !== 'undefined') { config.headers.Authorization = getTokenAUTH() as string; } return config; }, (error: AxiosError) => { return Promise.reject(error); } ); // 响应拦截 service.interceptors.response.use( (response: AxiosResponse) => { removePending(response.config); custom_options.loading && closeLoading(custom_options); // 关闭loading if ( custom_options.code_message_show && response.data && response.data.code !== 200 ) { ElMessage({ type: 'error', message: response.data.msg as string, }); return Promise.reject(response.data); // code不等于200, 页面具体逻辑就不执行了 } return custom_options.restore_data_format ? response.data : response; }, (error: AxiosError) => { error.config && removePending(error.config); custom_options.loading && closeLoading(custom_options); // 关闭loading custom_options.error_message_show && httpErrorStatusHandle(error); // 处理错误状态码 return Promise.reject(error); // 错误继续返回给到具体页面 } ); return service(axiosConfig); } export default Axios; /** * 处理异常 * @param {*} error */ function httpErrorStatusHandle(error: any) { // 处理被取消的请求 if (axios.isCancel(error)) return console.error('请求的重复请求:' + error.message); 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; } } if (error.message.includes('timeout')) message = '网络请求超时!'; if (error.message.includes('Network')) message = window.navigator.onLine ? '服务端异常!' : '您断网了!'; ElMessage({ type: 'error', message, }); } /** * 关闭Loading层实例 * @param {*} _options */ function closeLoading(_options: CustomOptions) { if (_options.loading && LoadingInstance._count > 0) LoadingInstance._count--; if (LoadingInstance._count === 0) { LoadingInstance._target.close(); LoadingInstance._target = null; } } /** * 储存每个请求的唯一cancel回调, 以此为标识 * @param {*} config */ function addPending(config: AxiosRequestConfig) { const pendingKey = getPendingKey(config); config.cancelToken = config.cancelToken || new axios.CancelToken((cancel: any) => { if (!pendingMap.has(pendingKey)) { pendingMap.set(pendingKey, cancel); } }); } /** * 删除重复的请求 * @param {*} config */ function removePending(config: AxiosRequestConfig) { const pendingKey = getPendingKey(config); if (pendingMap.has(pendingKey)) { const cancelToken: any = pendingMap.get(pendingKey); cancelToken(pendingKey); pendingMap.delete(pendingKey); } } /** * 生成唯一的每个请求的唯一key * @param {*} config * @returns */ function getPendingKey(config: AxiosRequestConfig) { const info: AxiosRequestConfig = config; if (typeof info.data === 'string') info.data = JSON.parse(info.data); // response里面返回的config.data是个字符串对象 return [info.url, info.method, JSON.stringify(info.params), JSON.stringify(info.data)].join('&'); }
使用(Typescript版本)
import request from "@/utils/Request"; /** * 获取专题 */ export const GetSpecial = (data: object) => request({ url: '/list', method: 'GET', params: data });
完整代码(中间件/网络请求拦截器-Js版本)
import axios from 'axios'; import {ElLoading, ElMessage} from 'element-plus'; const pendingMap = new Map(); const LoadingInstance = { _target: null, _count: 0 }; function getTokenAUTH() { return null } function Axios(axiosConfig, customOptions, loadingOptions) { const service = axios.create({ baseURL: process.env.VUE_APP_BASE_API, timeout: 1000 * 60, responseType: 'json' }); // 自定义配置 let custom_options = Object.assign({ repeat_request_cancel: true, // 是否开启取消重复请求, 默认为 true loading: false, // 是否开启loading层效果, 默认为false restore_data_format: true, // 是否开启简洁的数据结构响应, 默认为true error_message_show: true, // 是否开启接口错误信息展示,默认为true code_message_show: true, // 是否开启code不为0时的信息提示, 默认为false }, customOptions); // 请求拦截 service.interceptors.request.use( config => { removePending(config); custom_options.repeat_request_cancel && addPending(config); // 创建loading实例 if (custom_options.loading) { LoadingInstance._count++; if (LoadingInstance._count === 1) { LoadingInstance._target = ElLoading.service(loadingOptions); } } // 自动携带token if (getTokenAUTH() && typeof window !== "undefined") { config.headers.Authorization = getTokenAUTH(); } return config; }, error => { return Promise.reject(error); } ); // 响应拦截 service.interceptors.response.use( response => { removePending(response.config); custom_options.loading && closeLoading(custom_options); // 关闭loading if (custom_options.code_message_show && response.data && response.data.code !== 200) { ElMessage({ type: 'error', message: response.data.msg }) return Promise.reject(response.data); // code不等于200, 页面具体逻辑就不执行了 } return custom_options.restore_data_format ? response.data : response; }, error => { error.config && removePending(error.config); custom_options.loading && closeLoading(custom_options); // 关闭loading custom_options.error_message_show && httpErrorStatusHandle(error); // 处理错误状态码 return Promise.reject(error); // 错误继续返回给到具体页面 } ); return service(axiosConfig) } export default Axios; /** * 处理异常 * @param {*} error */ function httpErrorStatusHandle(error) { // 处理被取消的请求 if (axios.isCancel(error)) return console.error('请求的重复请求:' + error.message); 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 } } if (error.message.includes('timeout')) message = '网络请求超时!'; if (error.message.includes('Network')) message = window.navigator.onLine ? '服务端异常!' : '您断网了!'; ElMessage({ type: 'error', message }) } /** * 关闭Loading层实例 * @param {*} _options */ function closeLoading(_options) { if (_options.loading && LoadingInstance._count > 0) LoadingInstance._count--; if (LoadingInstance._count === 0) { LoadingInstance._target.close(); LoadingInstance._target = null; } } /** * 储存每个请求的唯一cancel回调, 以此为标识 * @param {*} config */ function addPending(config) { const pendingKey = getPendingKey(config); config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => { if (!pendingMap.has(pendingKey)) { pendingMap.set(pendingKey, cancel); } }); } /** * 删除重复的请求 * @param {*} config */ function removePending(config) { const pendingKey = getPendingKey(config); if (pendingMap.has(pendingKey)) { const cancelToken = pendingMap.get(pendingKey); cancelToken(pendingKey); pendingMap.delete(pendingKey); } } /** * 生成唯一的每个请求的唯一key * @param {*} config * @returns */ function getPendingKey(config) { let {url, method, params, data} = config; if (typeof data === 'string') data = JSON.parse(data); // response里面返回的config.data是个字符串对象 return [url, method, JSON.stringify(params), JSON.stringify(data)].join('&'); }
使用(Js版本)
import request from "@/utils/Request"; /** * 获取专题 */ export let GetSpecial = (data) => request({ url: '/list', method: 'GET', params: data });
sunshine15666