下面接着剖析一下踩到的坑以及办理思路
接着踩坑我按照之前传统的办法在返回拦截器里面进行token刷新,正常的数据可以返回,但是这个时候会有比较麻烦的地方,便是要求的数据可以在拦截器里面得到,但是不能渲染到界面上(看到这里的时候我是懵的)。
看一下代码
service.interceptors.response.use( response => { const res = response.data //刷新token的时候,可以从这里拦截到新数据,但是没有显示在页面上 console.log(39;拦截数据:',res) if (loadingInstance) { loadingInstance.close(); NProgress.done(); } switch (res.code) { case 200: return res case 401: router.push({ path: "/login", }) localStorage.clear(); Notification.error({ title: '令牌过期', message: '当前身份信息超过三天已失落效,请您重新登录', duration: 0 }); break; default: Message({ message: res.message || '要求缺点', type: 'error', duration: 5 1000 }) break; } }, error => { switch (error.response.status) { case 401: MessageBox.confirm('身份认证已过期,是否刷新本页连续浏览?', '提示', { confirmButtonText: '连续浏览', cancelButtonText: '退出登录', type: 'warning' }).then(() => { axios.post('/api/token/refresh/', { refresh: localStorage.getItem("retoken") }).then(response => { let res = response.data || {} if (res.code == 200) { let token = res.data.result; localStorage.setItem("token", token.access); localStorage.setItem("retoken", token.refresh); error.response.config.baseURL = ''; error.response.config.headers['Authorization'] = 'Bearer ' + localStorage.getItem("token") window.location.reload(); } else { router.push({ path: "/login", }) localStorage.clear(); Notification.error({ title: '令牌过期', message: '当前身份信息超过三天已失落效,请您重新登录', duration: 0 }); } }).catch(err => { router.push({ path: "/login", }) localStorage.clear(); Notification.error({ title: '认证失落败', message: '信息认证失落败,请重新登录', duration: 0 }); }) }).catch(() => { router.push({ path: "/login", }) Message({ message: '已退出', type: 'success', }) localStorage.clear(); }); break; case 404: Notification.error({ title: '404缺点', message: '做事器要求缺点,请联系管理员或稍后重试。缺点状态码:404', }); break default: Notification.error({ title: '要求缺点', message: '做事器要求缺点,请联系管理员或稍后重试', }); break; } if (loadingInstance) { loadingInstance.close(); NProgress.done(); } return Promise.reject(error); })
懵归懵,好在已经创造这个问题了,剩下的怎么办理呢?
当时想的是和后端合营,让后端直接发一个token过期的韶光戳给我,我直接把这个韶光戳放到localStrage里面,通过这个localStrage,直接在前端进行判断token的过期韶光进行要求拦截,如果当前要求的韶光大于了这个localStrage里面的韶光,就解释token过期了,我这边就须要重新要求token了,而不要后端去进行token的验证。
信心满满的弄了一下,创造行不通,token过期的时候,后端直接一个缺点401,前端就又回到解放前了。而且用韶光戳的办法很随意马虎涌现bug,且在前端进行token时长的验证,很随意马虎涌现问题。因此,我还是以为再研究一下上面那一段代码。
当然踩到坑不但是这个,还有百度和chatGPT,真的,看了一下没有找到一个可行的,总结一下紧张有以下几种
状态管理vuex路由router韶光戳(和我刚刚那种办法差不多)依赖注入inject刷新界面(我最开始那种办法,但是刷新的时候会涌现页面白屏,且用户如果在页面上有一些自己输入的数据也会被清空,用户体验感不好)以上办法我先不管行弗成,但是麻烦是肯定的,做前端讲究的就一个字:“
只能想想为什么拦截器里面可以得到数据,为什么页面位置得不到数据了
办理思路下面是我的办理思路,有不对的地方还请看到的大神指出来一下
当用户发起要求的时候,由于刷新token的http状态码是401,这个时候axios的相应拦截器就直接进行缺点捕获了,到了这里,由于数据已经返回了,但是由于是缺点数据,页面得到的这个数据不可用且当前要求已经结束了,当然这里对状态码401是进行处理了的(该当获取token了)。
采取普通的获取办法来获取token,由于异步的缘故原由,我们获取token的同时页面也在做刷新,token获取的同时,界面也刷新完毕了(但是是没有数据的,不做缺点捕获会报错),因此我们在获取token完毕,且用新的token去获取数据时,拦截器里面会有数据,但是界面已经安歇了,就不会把拦截器里面的新数据刷新到页面了。
因此这个地方须要对获取token的过程进行一下要求壅塞,把获取token的要求变成同步的。到这里就差不多了。直接把相应拦截器里面的error函数变成同步不就行了吗,async + await可以出来了。
以上是自己当时的想法,大略说来便是 页面刷新须要慢我获取token一步 ,通过这个办法也确实做到了无感刷新
希望以上的能帮助到你,有什么好的思路也欢迎评论区指出。
完全代码这个是用了2.13.2版本的element-ui以及nprogress的一个axios代码模块,包含了一个下载文件的模块。
如果须要的话可以根据自己的需求来进行修正
import axios from 'axios'import { Message, Loading, Notification,} from 'element-ui'import NProgress from 'nprogress' // progress barimport 'nprogress/nprogress.css' // progress bar styleimport router from '@/router/index'const baseURL = '/api'const service = axios.create({ baseURL, timeout: 6000})NProgress.configure({ showSpinner: false}) // NProgress Configurationlet loadingInstance = undefined;service.interceptors.request.use( config => { NProgress.start() loadingInstance = Loading.service({ lock: true, text: '正在加载,请稍候...', spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.3)' }) config.headers['Authorization'] = 'Bearer ' + localStorage.getItem("token") return config; }, error => { return Promise.reject(error) })service.interceptors.response.use( response => { const res = response.data if (loadingInstance) { loadingInstance.close(); NProgress.done(); } switch (res.code) { case 200: return res case 401: router.push({ path: "/login", }) localStorage.clear(); Notification.error({ title: '认证失落效', message: '当前身份信息超过三天已失落效,请您重新登录', duration: 0 }); break; default: Message({ message: res.message || '要求缺点', type: 'error', duration: 5 1000 }) break; } }, async error => { switch (error.response.status) { case 401: const err401Data = error.response.data || {} if (err401Data.code !== "token_not_valid") { router.push({ path: "/login", }) localStorage.clear(); Notification.error({ title: '认证失落败', message: '身份信息认证失落败,请您重新登录', duration: 0 }); return } try { const res = await service.post('/token/refresh/', { refresh: localStorage.getItem("retoken") }) if (res.code == 200) { let token = res.data.result; localStorage.setItem("token", token.access); localStorage.setItem("retoken", token.refresh); error.response.config.baseURL = '' error.response.config.headers['Authorization'] = 'Bearer ' + localStorage.getItem("token") return service(error.response.config) } else { router.push({ path: "/login", }) localStorage.clear(); Notification.error({ title: '认证失落败', message: '当前身份认证信息已失落效,请您重新登录', duration: 0 }); } } catch (error) { router.push({ path: "/login", }) localStorage.clear(); Notification.error({ title: '认证失落败', message: '身份认证失落败,请您重新登录,失落败缘故原由:' + error.message, duration: 0 }); } break case 404: Notification.error({ title: '404缺点', message: '做事器要求缺点,请联系管理员或稍后重试。缺点状态码:404', }); break default: Notification.error({ title: '要求缺点', message: '做事器要求缺点,请联系管理员或稍后重试', }); break; } if (loadingInstance) { loadingInstance.close(); NProgress.done(); } return Promise.reject(error); })// 文件下载通用办法export const requestFile = axios.create({ baseURL, timeout: 0, //关闭超时时间});requestFile.interceptors.request.use((config) => { config.headers['Authorization'] = 'Bearer ' + localStorage.getItem("token") //携带的要求头 config.responseType = 'blob'; loadingInstance = Loading.service({ lock: true, text: '正不才载,请稍候...', spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.3)' }) return config;});requestFile.interceptors.response.use( (response) => { let res = response.data; if (loadingInstance) { loadingInstance.close() } // const contentType = response.headers['content-type'];//获取返回的数据类型 let blob = new Blob([res], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" //文件下载以及上传类型为 .xlsx }); let url = window.URL.createObjectURL(blob); // 创建一个链接元素 let link = document.createElement('a'); link.href = url; link.download = '产品列表.xlsx'; // 自定义文件名 link.click(); }, (err) => { Message({ message: '操作失落败,请联系管理员', type: 'error', }) if (loadingInstance) { loadingInstance.close() } });export default service;
作者:讷言丶链接:https://juejin.cn/post/7260700447170101306