TNBLOG
首页
博客
视频
资源
问答
猿趣
手机
关于
搜索
收藏
便签
笔记
消息
创作
登录
剑轩
故如虹,知恩;故如月,知明
博主信息
排名
6
文章
6
粉丝
16
评论
8
文章类别
CSS
15篇
微服务
41篇
Git
14篇
.NET
102篇
移动开发
33篇
软件架构
23篇
.NET Core
119篇
.NET MVC
11篇
英语
3篇
随笔
86篇
Bootstrap
3篇
Redis
21篇
编辑器
10篇
Js相关
15篇
虚拟化
8篇
更多
Oracle
7篇
Python
14篇
数据库
26篇
EF
17篇
微信
3篇
前端
151篇
消息队列
6篇
docker
41篇
多线程
1篇
Java
4篇
软件基础
2篇
C++
2篇
WCF
7篇
Linux
7篇
nginx
5篇
K8S
9篇
ABP
2篇
最新文章
最新评价
{{item.articleTitle}}
{{item.blogName}}
:
{{item.content}}
关于我们
ICP备案 :
渝ICP备18016597号-1
网站信息:
2018-2024
TNBLOG.NET
技术交流:
群号656732739
联系我们:
contact@tnblog.net
欢迎加群
欢迎加群交流技术
原
vue3使用axios的请求封装与跨域配置
1045
人阅读
2022/7/29 18:06
总访问:
3967494
评论:
0
收藏:
0
手机
分类:
前端
tn2>以前vue2当中的详细的请求封装以及跨域的可以参考: https://www.tnblog.net/aojiancc2/article/details/4751 其实逻辑基本都是一致的,里边封装的步骤列得比较详细 [TOC] ### 先进行请求封装 在src下创建一个common文件夹里边创建一个request.js,加入封装代码。当然文件夹放哪里根据自己的需要来就行了。 ##### 加入简单封装的代码 ``` import axios from "axios"; import qs from "qs"; // vue3下的element-plus import { ElLoading , ElMessage } from "element-plus"; const loading = { // loading加载对象 loadingInstance: null, // 打开加载 open(loadtext) { if (this.loadingInstance === null) { // 如果实例 为空,则创建 this.loadingInstance = ElLoading.service({ text: loadtext, // '加载中...', // 加载图标下的文字 spinner: "el-icon-loading", // 加载图标 background: "rgba(0, 0, 0, 0.5)", // 背景色 customClass: "loading", // 自定义样式的类名 }); } }, // 关闭加载 close() { // 不为空时, 则关闭加载窗口 if (this.loadingInstance !== null) { this.loadingInstance.close(); } this.loadingInstance = null; }, }; axios.defaults.timeout = 300000; // 设置超时时间 // 配置请求头数据格式 // axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded' // 请求拦截器 // 请求拦截器 axios.interceptors.request.use( (axiosconfig) => { // 请求地址统一增加一个webapi,因为后台那个代理配置里边有加上webapi的前缀 //axiosconfig.url = "/webapi" + axiosconfig.url; //从环境变量读取,线下访问接口增加webapi前缀,上线就不增加 // axiosconfig.url = process.env.VUE_APP_BASE_API + axiosconfig.url; axiosconfig.url = "" + axiosconfig.url; //axiosconfig.headers.Authorization = "Bearer " + token; return axiosconfig; }, (err) => { loading.close(); // 关闭加载窗口 return Promise.reject(err); } ); // 响应拦截器 axios.interceptors.response.use( (res) => { //console.log("统一响应了"); loading.close(); // 关闭加载窗口 // 如果token过期了就直接跳转到登录 // if ( // (res.code === 401 || res.code === 500 || res.code === 403) && // !sessionStorage.getItem("401show") // ) { // // to re-login // sessionStorage["401show"] = true; // ElMessage.confirm("登录状态已过期", "登录提示", { // confirmButtonText: "重新登录", // cancelButtonText: "取消", // type: "warning", // }) // .then(() => { // sessionStorage.clear("401show"); // // 跳转到登录页 // location.href = "/#/login?redirect=/school-dashboard#/zuxia/index"; // }) // .catch(() => { // sessionStorage.clear("401show"); // }); // } return res; }, (err) => { loading.close(); // 关闭加载窗口 return Promise.reject(err); } ); const request = { get(url, data, loadtext) { // 判断有没有参数,有参数就把参数加上 if (data) { url = url + "?" + qs.stringify(data); } if (loadtext && loadtext.length > 0) { loading.open(loadtext); // 打开加载窗口 } return new Promise((resolve, reject) => { axios .get(url) .then(function (response) { // console.log("封装的方法数据回来了"); // console.log(response) if (response.status === 200 && response.data.code === 200) { resolve(response.data); } else { // 上面的判断要根据实际情况修改判断对哦,不然使用else里边的reject输出,虽然结果也能正确输出,但是浏览器上会提示Uncaught (in promise),也不能继续正确的向下执行了。 reject(response.data); } }) .catch((e) => { reject(e); }); }); }, post(url, data, loadtext) { if (loadtext && loadtext.length > 0) { loading.open(loadtext); // 打开加载窗口 } return new Promise((resolve, reject) => { axios .post(url, data) .then(function (response) { if (response.status === 200 && response.data.code === 200) { resolve(response.data); } else { reject(response.data); } }) .catch((e) => { reject(e); }); }); }, }; export default request; ``` ##### 这个是更完善一点的封装方法 增加了put,delete等方法的封装 ``` import axios from 'axios' import qs from 'qs' // vue3下的element-plus import { ElLoading, ElMessage } from 'element-plus' // 后台接口返回成功的状态码,需要根据自己的接口修改 const successCode = 200 const loading = { // loading加载对象 loadingInstance: null, // 打开加载 open(loadtext) { if (this.loadingInstance === null) { // 如果实例 为空,则创建 this.loadingInstance = ElLoading.service({ text: loadtext, // '加载中...', // 加载图标下的文字 spinner: 'el-icon-loading', // 加载图标 background: 'rgba(0, 0, 0, 0.5)', // 背景色 customClass: 'loading' // 自定义样式的类名 }) } }, // 关闭加载 close() { // 不为空时, 则关闭加载窗口 if (this.loadingInstance !== null) { this.loadingInstance.close() } this.loadingInstance = null } } axios.defaults.timeout = 300000 // 设置超时时间 // 配置请求头数据格式 // axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded' // 请求拦截器 axios.interceptors.request.use( (axiosconfig) => { // 请求地址统一增加一个webapi,因为后台那个代理配置里边有加上webapi的前缀 //axiosconfig.url = "/webapi" + axiosconfig.url; //从环境变量读取,线下访问接口增加webapi前缀,上线就不增加 // axiosconfig.url = process.env.VUE_APP_BASE_API + axiosconfig.url; axiosconfig.url = '' + axiosconfig.url // console.log("请求的地址2",axiosconfig.url) // 测试token , 获取token的方法换成自己的写法即可 let token = "eyJhbGciOiJSUzI1NiIsImtpZCI6IkU0QUU1Rk...." axiosconfig.headers.Authorization = "Bearer " + token; return axiosconfig }, (err) => { loading.close() // 关闭加载窗口 return Promise.reject(err) } ) // 响应拦截器 axios.interceptors.response.use( (res) => { //console.log("统一响应了",res); loading.close() // 关闭加载窗口 if(res.data.code!==successCode) { ElMessage({ message: res.data.msg, type: 'error' }) } // 如果token过期了就直接跳转到登录 // if ( // (res.code === 401 || res.code === 500 || res.code === 403) && // !sessionStorage.getItem("401show") // ) { // // to re-login // sessionStorage["401show"] = true; // ElMessage.confirm("登录状态已过期", "登录提示", { // confirmButtonText: "重新登录", // cancelButtonText: "取消", // type: "warning", // }) // .then(() => { // sessionStorage.clear("401show"); // // 跳转到登录页 // location.href = "/#/login?redirect=/school-dashboard#/zuxia/index"; // }) // .catch(() => { // sessionStorage.clear("401show"); // }); // } return res }, (err) => { loading.close() // 关闭加载窗口 console.log(err) ElMessage({ message: err, type: 'error' }) return Promise.reject(err) } ) const request = { get(url, data, loadtext) { // 判断有没有参数,有参数就把参数加上 if (data) { url = url + '?' + qs.stringify(data) } console.log("请求的地址",url) if (loadtext && loadtext.length > 0) { loading.open(loadtext) // 打开加载窗口 } return new Promise((resolve, reject) => { axios .get(url) .then(function (response) { // console.log("封装的方法数据回来了"); // console.log(response) if (response.status === 200 && response.data.code === successCode) { resolve(response.data) } else { // 上面的判断要根据实际情况修改判断对哦,不然使用else里边的reject输出,虽然结果也能正确输出,但是浏览器上会提示Uncaught (in promise),也不能继续正确的向下执行了。 reject(response.data) } }) .catch((e) => { reject(e) }) }) }, post(url, data, loadtext) { if (loadtext && loadtext.length > 0) { loading.open(loadtext) // 打开加载窗口 } return new Promise((resolve, reject) => { axios .post(url, data) .then(function (response) { if (response.status === 200 && response.data.code === successCode) { resolve(response.data) } else { reject(response.data) } }) .catch((e) => { reject(e) }) }) }, put(url, data, loadtext) { if (loadtext && loadtext.length > 0) { loading.open(loadtext) // 打开加载窗口 } return new Promise((resolve, reject) => { axios .put(url, data) .then(function (response) { if (response.status === 200 && response.data.code === successCode) { resolve(response.data) } else { reject(response.data) } }) .catch((e) => { reject(e) }) }) }, delete(url, data, loadtext) { if (loadtext && loadtext.length > 0) { loading.open(loadtext) // 打开加载窗口 } return new Promise((resolve, reject) => { axios .delete(url, data) .then(function (response) { if (response.status === 200 && response.data.code === successCode) { resolve(response.data) } else { reject(response.data) } }) .catch((e) => { reject(e) }) }) } } export default request ``` tip:其他的封装方法比如ts版本的请求封装可以参考下面的写法 ### 在配置好跨域 vue3的跨域配置在vite.config.js中,配置方法和以前几乎完全一致,根据自己的需求修改即可。 ![](https://img.tnblog.net/arcimg/aojiancc2/89f301d0490f4bd2befa1aada15288fa.png) ### 直接使用封装的代码调用接口 在需要使用的组件引入封装的js: ``` import request from '@/common/request' ``` **把onMounted这些也引入一下:** ``` import { reactive, toRefs, onMounted } from 'vue' ``` **在onMounted中调用接口** ``` const initData = () =>{ //测试接口访问 request.get('/api/v1/Home/1',{}).then(res => { console.log("测试数据返回") console.log(res) }) } onMounted(() => { initData() }) ``` 数据被成功输出了: ![](https://img.tnblog.net/arcimg/aojiancc2/bfad64c626d84863ab42202293659d35.png) 注意要把跨域配置好,不然会报跨域相关的错误。 ### 全局引入封装的请求js 在main.js中加入相关代码 **vue2中的写法:** ``` import request from "./common/request.js"; Vue.prototype.$http = request; ``` **vue3不能这样写了,应该这样写:** ``` import request from "./common/request.js"; const app = createApp(App) // vue3中要使用下面的写法 app.config.globalProperties.$http = request ``` #### 调用方法 先引入: ``` import { reactive, toRefs, getCurrentInstance, onMounted } from 'vue' let internalInstance = getCurrentInstance() as any const $http = internalInstance.appContext.config.globalProperties.$http ``` 调用: ``` const initData = () => { //测试接口访问 $http.get('/api/v1/Home/1').then(res => { console.log("测试数据返回") console.log(res) }) } onMounted(() => { initData() }) ``` #### 也可以使用异步的方式调用接口 ``` const fetchData = async () => { const res = await $http.get('/api/v1/Home/1') console.log("测试数据返回了") console.log(res); } onMounted(() => { fetchData() }) ``` 直接使用axios调用接口也是可以异步使用的 ``` const fetchData = async () => { // const res = await $http.get('/api/v1/Home/1') // console.log("测试数据返回了") // console.log(res); const res = await axios.get('/api/v1/Home/1') console.log("测试数据返回了.") console.log(res.data); } onMounted(() => { fetchData() }) ``` ### 单独提出来api方法 其实现在调用api也可以不用做成全局的方式,更多的是使用把api请求的方法单独提出来写 **首先在src文件夹下面创建好api,然后加入需要的js文件:** ![](https://img.tnblog.net/arcimg/aojiancc2/c38fe6ed0c9c4a9e900b8c6b775046ff.png) 封装好需要调用api的方法: ``` import request from '@/common/request' /** * @method getArticle 获取文章信息 * @param {*} data * @returns */ export function getArticle(data) { return request.get('/api/v1/Home/1',data) } ``` **调用:** 先引入封装的js: ``` import { getArticle } from '@/api/article' ``` 使用异步的方式调用方法: ``` const fetchData = async () => { const res = await getArticle({}) console.log("测试数据返回了..") console.log(res); } onMounted(() => { fetchData() }) ``` 使用then的方式调用 ``` const fetchData = () => { getArticle({}).then(res => { console.log("测试数据返回了...") console.log(res) }) } onMounted(() => { fetchData() }) ``` **如果返回的数据是这种格式** ![](https://img.tnblog.net/arcimg/aojiancc2/6bc261a7163b4600a4f8eccb574cd285.png) 取list和total可以这种取: ``` const fetchData = async () => { const { data: { list, total }, } = await getInquiryInfo({}) console.log("测试数据返回了..") console.log(list); console.log(total); } ``` ### 完善请求封装 ##### 把请求封装修改为ts版本 ``` import axios from 'axios' import qs from 'qs' // vue3下的element-plus import { ElLoading, ElMessage } from 'element-plus' // 后台接口返回成功的状态码,需要根据自己的接口修改 const successCode = 0 // loading加载对象 // let loadingInstance: any const loading = { // loading加载对象 loadingInstance:null as any, // 打开加载 open(loadtext: any) { //if (this.loadingInstance === null) { // 如果实例 为空,则创建 this.loadingInstance = ElLoading.service({ text: loadtext, // '加载中...', // 加载图标下的文字 // spinner: 'el-icon-loading', // 加载图标 background: 'rgba(0, 0, 0, 0.6)', // 背景色 customClass: 'loading' // 自定义样式的类名 }) //} }, // 关闭加载 close() { // 不为空时, 则关闭加载窗口 if (this.loadingInstance) { this.loadingInstance.close() } // this.loadingInstance = null } } axios.defaults.timeout = 300000 // 设置超时时间 // 配置请求头数据格式 // axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded' // 请求拦截器 axios.interceptors.request.use( (axiosconfig) => { // 请求地址统一增加一个webapi,因为后台那个代理配置里边有加上webapi的前缀 //axiosconfig.url = "/webapi" + axiosconfig.url; //从环境变量读取,线下访问接口增加webapi前缀,上线就不增加 // axiosconfig.url = process.env.VUE_APP_BASE_API + axiosconfig.url; axiosconfig.url = '' + axiosconfig.url // console.log("请求的地址2",axiosconfig.url) // 测试token , 获取token的方法换成自己的写法即可 let token = "eyJhbGciOiJSUzI1NiIsImtpZCI" axiosconfig.headers.Authorization = "Bearer " + token; return axiosconfig }, (err) => { loading.close() // 关闭加载窗口 return Promise.reject(err) } ) // 响应拦截器 axios.interceptors.response.use( (res) => { //console.log("统一响应了",res); loading.close() // 关闭加载窗口 if (res.data.code !== successCode) { ElMessage({ message: res.data.msg, type: 'error' }) } // 如果token过期了就直接跳转到登录 // if ( // (res.code === 401 || res.code === 500 || res.code === 403) && // !sessionStorage.getItem("401show") // ) { // // to re-login // sessionStorage["401show"] = true; // ElMessage.confirm("登录状态已过期", "登录提示", { // confirmButtonText: "重新登录", // cancelButtonText: "取消", // type: "warning", // }) // .then(() => { // sessionStorage.clear("401show"); // // 跳转到登录页 // location.href = "/#/login?redirect=/school-dashboard#/zuxia/index"; // }) // .catch(() => { // sessionStorage.clear("401show"); // }); // } return res }, (err) => { loading.close() // 关闭加载窗口 console.log(err) ElMessage({ message: err, type: 'error' }) return Promise.reject(err) } ) const request = { get(url: any, data: any, loadtext: any="") { // 判断有没有参数,有参数就把参数加上 if (data) { url = url + '?' + qs.stringify(data) } if (loadtext && loadtext.length > 0) { loading.open(loadtext) // 打开加载窗口 } return new Promise((resolve, reject) => { axios .get(url) .then(function (response) { // console.log("封装的方法数据回来了"); // console.log(response) if (response.status === 200 && response.data.code === successCode) { resolve(response.data) } else { // 上面的判断要根据实际情况修改判断对哦,不然使用else里边的reject输出,虽然结果也能正确输出,但是浏览器上会提示Uncaught (in promise),也不能继续正确的向下执行了。 reject(response.data) } }) .catch((e) => { reject(e) }) }) }, post(url: any, data: any, loadtext: any="") { if (loadtext && loadtext.length > 0) { loading.open(loadtext) // 打开加载窗口 } return new Promise((resolve, reject) => { axios .post(url, data) .then(function (response) { if (response.status === 200 && response.data.code === successCode) { resolve(response.data) } else { reject(response.data) } }) .catch((e) => { reject(e) }) }) }, put(url: any, data: any, loadtext: any="") { if (loadtext && loadtext.length > 0) { loading.open(loadtext) // 打开加载窗口 } return new Promise((resolve, reject) => { axios .put(url, data) .then(function (response) { if (response.status === 200 && response.data.code === successCode) { resolve(response.data) } else { reject(response.data) } }) .catch((e) => { reject(e) }) }) }, delete(url: any, data: any, loadtext: any="") { if (loadtext && loadtext.length > 0) { loading.open(loadtext) // 打开加载窗口 } return new Promise((resolve, reject) => { axios .delete(url, data) .then(function (response) { if (response.status === 200 && response.data.code === successCode) { resolve(response.data) } else { reject(response.data) } }) .catch((e) => { reject(e) }) }) } } export default request ``` ##### 在ts中使用封装的请求也是一样的 引入封装的request之后使用方法如下。其实都是一样的,就是要注意一下ts中的类型检查,类型不确定时使用可以使用any,unknown等类型来处理,或者使用类型断言。 ``` const getTasksList = async () => { const result: any = await request.get('/growing/api/Tasks/GetTasksPage', state.pageParam, "请求") console.log(result) state.tasksList = result.data.data // 请求的api地址,以及返回数据的格式自己根据自己的修改 // request.get('/education/api/Feedback/GetSchools', state.pageParam).then((res: any) => { // console.log('获取任务') // console.log(res) // state.tasksList = res.data.data // }) } ``` ### vue3的一个模板vue3-admin-template里边自带封装的request请求 贴一下他这个封装的代码,也可以考虑借鉴: ``` import axios from 'axios' import { ElMessage, ElMessageBox } from 'element-plus' import { useUserStore } from '@/store/user' import { getCookies } from '@/utils/storage' import defaultSettings from '@/settings' // 业务请求 const request = axios.create({ baseURL: defaultSettings.isMockData ? '' : import.meta.env.VITE_APP_BASE_API, // url = base url + request url // withCredentials: true, // send cookies when cross-domain requests timeout: 5000 // request timeout }) // const request = axios.create({ // baseURL: "", // url = base url + request url // // withCredentials: true, // send cookies when cross-domain requests // timeout: 5000 // request timeout // }) // request interceptor request.interceptors.request.use( (config) => { // do something before request is sent const userStore = useUserStore() if (userStore.token) { // let each request carry token // ['X-Token'] is a custom headers key // please modify it according to the actual situation config.headers['X-Token'] = getCookies('Fanqie-Token') } return config }, (error) => { // do something with request error console.log(error) // for debug return Promise.reject(error) } ) // response interceptor request.interceptors.response.use( /** * If you want to get http information such as headers or status * Please return response => response */ /** * Determine the request status by custom code * Here is just an example * You can also judge the status by HTTP Status Code */ (response) => { const res = response.data // if the custom code is not 20000, it is judged as an error. if (res.code !== 20000 && res.code!=200) { ElMessage({ message: res.message || 'Error', type: 'error', duration: 5 * 1000 }) // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired; if (res.code === 50008 || res.code === 50012 || res.code === 50014) { // to re-login ElMessageBox.confirm( 'You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', { confirmButtonText: 'Re-Login', cancelButtonText: 'Cancel', type: 'warning' } ).then(() => { const userStore = useUserStore() userStore.resetToken.then(() => { location.reload() }) }) } return Promise.reject(new Error(res.message || 'Error')) } else { return res } }, (error) => { console.log('err' + error) // for debug ElMessage({ message: error.message, type: 'error', duration: 5 * 1000 }) return Promise.reject(error) } ) /** * 用于请求 gitee 的数据 */ const requestA = axios.create({ baseURL: import.meta.env.VITE_APP_GITEE_BASE_API, // url = base url + request url timeout: 60 * 1000 }) requestA.interceptors.request.use( (config) => { return config }, (error) => { console.log(error) return Promise.reject(error) } ) requestA.interceptors.response.use( (response) => { const { data, status, statusText } = response if (status === 200) { return data } else { ElMessage({ message: statusText || 'Error', type: 'error', duration: 5 * 1000 }) return false } }, (error) => { console.log('err' + error) ElMessage({ message: error.message, type: 'error', duration: 5 * 1000 }) return Promise.reject(error) } ) export { request, requestA } ``` **他这个封装的api接口请求示例:** 也是像上面说的那样单独提出来一个文件写的 ``` import { request } from '@/utils/request' /** * @method addUserLogin 登录 * @param {*} data * @returns */ export function addUserLogin(data) { return request({ url: '/user-login', method: 'post', data }) } /** * @method addUserInfo 用户信息 * @param {*} data * @returns */ export function addUserInfo(data) { return request({ url: '/user-info', method: 'post', data }) } ``` 调用方法和前面的一样就不在累述了
欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739
👈{{preArticle.title}}
👉{{nextArticle.title}}
评价
{{titleitem}}
{{titleitem}}
{{item.content}}
{{titleitem}}
{{titleitem}}
{{item.content}}