【Geek议题】合理的VueSPA架构讨论(下)
接上篇《【Geek议题】合理的VueSPA架构讨论(上)》传送门。
自动化维护登录状态
登录状态标识符跟token类似,都是需要自动维护有效期,但也有些许不同,获取过程只在用户登录或注册的时候,不需要自动获取。
本人比较推荐使用公共状态管理vuex进行自动化管理,并配合路由钩子,减少代码编写时的顾虑。
妙用公共状态管理维护userId
示例中公共状态管理中的user模块里定义了userIdObj,其中包含了userId登录状态标识符和过期时间。
维护userId是否过期主要是通过vuex中的getter来实现。
const getters = {
getUserId: (_state) => {
// 获取公共状态中的userIdObj
const userIdObj = {
..._state.userIdObj,
};
// 是否过期标识
let isExpire = false;
// 判断是否过期
if (userIdObj && userIdObj.userId) {
isExpire = new Date().getTime() - userIdObj.expireTime > -10000;
}
// 如果过期则返回空字符串(不一定)
if (!userIdObj || !userIdObj.userId || isExpire) {
return '';
}
// 没过期则返回userId
return userIdObj.userId;
},
};
路由钩子中处理userId
回顾上篇中全局的路由钩子router.beforeEach
,当目标路由元信息requiresAuth为true则表示,这个路由必须有登录状态才能访问,这时候就会进行登录状态检查。处理思路如下:
- 使用上面定义的getter方法获取userId;
- 如果能获取到则说明有有效的userId,则时候即可跳转到目标页;
- 如果获取到空字符串,则说明userId无效或userId不存在,跳转至登录页面。
【PS】示例这里的处理还不完美,最好跳转登录前保存好目标路由,登录成功就直接跳转去该路由。
router.beforeEach((to, from, next) => {
// ...
// 检查登录状态
if (to.meta.requiresAuth) {
console.log('目标路由需要登录状态');
if (!store.getters.getUserId) {
console.log('内存无登录信息,尝试在本地存储中找');
const localUserIdObj = JSON.parse(localStorage.getItem('userIdObj'));
if (localUserIdObj) {
// 如果本地存储中有userIdObj,则提交到公共状态
store.commit('setUserIdObj', localUserIdObj);
}
}
// 再次检查公共状态里有没有userId
if (!store.getters.getUserId) {
console.log('依旧无登录信息');
router.push({
name: 'userLogin',
});
}
}
next();
});
”页面”中获取登录状态
在“页面”中获取userId也很简单,使用计算属性是最好的,返回的userId具有响应性,这做的好处也是为了实时将登录状态反应到页面上,才不会出现显示已登录,但用户刷新一下才能知道登录状态已过期的尴尬情况。
【PS】一些需要用户登录状态的api函数,也是通过这样的方法获取并使用。当然,建议在非首屏加载使用的api函数(比如提交表单),需要在调用前,检查一下userId还存不存在,以免出错。
computed: {
// 获取登录状态
userId() {
return this.$store.getters.getUserId;
},
},
使用公共状态管理维护连接
有时会有需要取消请求的需求,比如上传文件耗时过长,用户不想等,这时候就必须有取消的功能。
上篇提到的axios已经提供了一个基于CancelToken的取消机制,这里我们要配合vuex实现对全局连接的实时监控。
【PS】示例的接口名称都是在写api函数的时候定义好的,想要更加灵活,可以每次请求都单独指定名字。
公共状态管理配置
示例中给公共状态下的com模块添加了cancelToken数组,用来保存发起的连接的名称和source(取消标记),并提供了如下三个mutations方法
// 增加cancelToken
addCancelToken(_state, cancelToken) {
_state.cancelToken.push(cancelToken);
const arr = _state.cancelToken;
_state.cancelToken = arr;
},
// 删除指定名字的cancelToken
deleteCancelToken(_state, name) {
_state.cancelToken.some((i, index) => {
if (i.name === name) {
_state.cancelToken.splice(index, 1);
return true;
}
return false;
});
},
// 清空cancelToken
clearCancelToken(_state) {
_state.cancelToken.forEach((i) => {
if (i.source && typeof i.source.cancel === 'function') {
i.source.cancel(`cancel${name}`);
}
});
_state.cancelToken = [];
},
请求拦截器配置
基本思路:
- 在“请求发起前拦截器”中获取到source(取消标记),写入请求配置,并提交名称和source到公共状态管理;
- 这时候通过查询公共状态中是否有这个名字的连接就可以获取到source进行取消;
- 在“响应拦截器”中我们将已经成功的请求在公共状态管理中移除。
// 请求发起前拦截器
myAxios.interceptors.request.use((_config) => {
const config = _config;
const source = axios.CancelToken.source();
// 获取cancelToken
config.cancelToken = source.token;
// 取消请求标记保存
store.commit('addCancelToken', {
name: config.name,
source,
});
return config;
}, () => {
// 异常处理
console.error('请求发起前拦截器异常');
});
// 响应拦截器
myAxios.interceptors.response.use((response) => {
// 删除取消标记
store.commit('deleteCancelToken', response.config.name);
console.log(response);
return response;
}, (error) => {
console.error(error);
// 清理取消标记
store.commit('clearCancelToken');
return Promise.reject(error);
});
代码中使用
使用计算属性获取cancelToken数组,这里是响应式的,所有我们其实可以知道现在有多少个请求还未完成了。
【PS】实时对全局请求的监控已经实现,其实可以做的扩展就很多了,比如可以全局化loading的显示,只要数组内一直不为空持续一段时间就可以判断需要显示loading,如果为空则关闭loading。
computed: {
// 获取连接列表
cancelToken() {
return this.$store.state.com.cancelToken;
},
},
遍历这个数组,查找到对应名字的连接就可以取消了。
this.cancelToken.forEach((i) => {
console.log(i);
if (i.name === '上传文件' && typeof i.source.cancel === 'function') {
console.log('取消上传');
i.source.cancel(`cancel${name}`);
}
});
其他细节技巧
挂载常用工具到vue原型上减少引用
在初始化Vue的根组件前,给Vue的原型链上添加常用的工具,可以方便在vue文件中使用。这样做会影响所有Vue示例推荐只在单页面应用中使用。
比如下面以我们的api集为例,这样在vue文件中this.$api
就可以使用我们的api集,不需要重复引用。
// 将api模块挂载进vue方便在this调用
Vue.prototype.$api = api;
批量导入过滤器
在util文件夹下可以新建一个专门用来存过滤器的filter.js,然后批量导入的全局过滤器中。
import * as filters from './util/filter';
Object.keys(filters).forEach(k => Vue.filter(k, filters[k]));
【Geek议题】合理的VueSPA架构讨论(下)的更多相关文章
- 【Geek议题】合理的VueSPA架构讨论(上)
前言 web前端发展到现代,已经不再是严格意义上的后端MVC的V层,它越来越向类似客户端开发的方向发展,已独立拥有了自己的MVVM设计模型.前后端的分离也使前端人员拥有更大的自由,可以独立设计客户端部 ...
- Kubernetes 架构(下)- 每天5分钟玩转 Docker 容器技术(121)
上一节我们讨论了 Kubernetes 架构 Master 上运行的服务,本节讨论 Node 节点. Node 是 Pod 运行的地方,Kubernetes 支持 Docker.rkt 等容器 Run ...
- Kubernetes 架构(下)【转】
上一节我们讨论了 Kubernetes 架构 Master 上运行的服务,本节讨论 Node 节点. Node 是 Pod 运行的地方,Kubernetes 支持 Docker.rkt 等容器 Run ...
- (转载)RESTful架构风格下的4大常见安全问题
转载自<RESTful架构风格下的4大常见安全问题>,作者:马伟 伴随着RESTful架构风格的大量应用微服务架构的流行,一些本来难以察觉到的安全问题也逐渐开始显现出来.在我经历过的各种采 ...
- 最近研究了一个.NET的DHT网络搜索引擎,顺便重新整理了下引擎思路,供大家分享讨论下。
最近研究了一个.NET的DHT网络搜索引擎,顺便重新整理了下引擎思路,供大家分享讨论下.
- 微信架构 & 支付架构(下)
微信架构 & 支付架构(下) 3. 管理网络请求 首先看看原来 iOS 处理支付网络请求的缺陷: 原来支付的请求,都是通过一个单例网络中心去发起请求,然后收到回包后,通过抛通知,或者调用闭包的 ...
- Pass Infrastructure基础架构(下)
Pass Infrastructure基础架构(下) pass注册 PassRegistration该类在示例中简要显示了各种pass类型的定义 .该机制允许注册pass类,以便可以在文本pass管 ...
- 【Geek议题】当年那些风骚的跨域操作
前言 现在cross-origin resource sharing(跨域资源共享,下简称CORS)已经十分普及,算上IE8的不标准兼容(XDomainRequest),各大浏览器基本都已支持,当年为 ...
- Thrift架构~windows下安装和Hello World及编码引起的错误
最近开始正式接触Thrift架构,很牛B的技术,它被apache收纳了,属于开源中的一员,呵呵. 概念: Thrift源于大名鼎鼎的facebook之手,在2007年facebook提交Apache基 ...
随机推荐
- Java数据结构之单向环形链表(解决Josephu约瑟夫环问题)
1.Josephu(约瑟夫.约瑟夫环)问题: 设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m ...
- QT linux下显示中文的问题
如果中文显示为乱码,那么是字符集不对. 应该设置字符集: QTextCodec::setCodecForLocale(QTextCodec::codecForName("GBK") ...
- SSM框架中数据库无法连接的问题
首先是SSM框架中所有的配置都是没有问题的,而且项目在其他人的环境上也能正常访问数据库:那么最有可能的就是数据库版本的问题导致数据库连接不上,服务器给我的报错是: 15:37:25.902 [C3P0 ...
- Python 入门之 Python三大器 之 生成器
Python 入门之 Python三大器 之 生成器 1.生成器 (1)什么是生成器? 核心:生成器的本质就是一个迭代器 迭代器是Python自带的 生成器程序员自己写的一种迭代器 def func( ...
- C#GC垃圾回收和析构函数和IDisposable的使用
一,什么是GC 1,GC是垃圾回收器,一般来说系统会自动检测不会使用的对象或变量进行内存的释放,不需要手动调用,用Collect()就是强制进行垃圾回收,使内存得到及时的释放,让程序效率更高. 2,G ...
- 56. Merge Intervals (JAVA)
Given a collection of intervals, merge all overlapping intervals. Example 1: Input: [[1,3],[2,6],[8, ...
- xcode自动生成代码片段
一.什么是代码片段 当在Xcode中输入dowhile并回车后,Xcode会出现下图所示的提示代码: 这就是代码片段,目的是使程序员以最快的速度输入常用的代码片段,提高编程效率.该功能是从Xcode4 ...
- python基础知识的入门介绍
一.什么是编程语言 任何词语都是一种高度的概括和总结,所以找关键字.如下: (1)1.什么是"语言":一个人与另一个人沟通的介质 2人将自己的思维逻辑和想法通过计算机能过识别的语言 ...
- 使用Medusa美杜莎暴力破解SSH密码
使用Medusa美杜莎暴力破解SSH密码 1.Medusa简介 Medusa(美杜莎)是一个速度快,支持大规模并行,模块化的爆力破解工具.可以同时对多个主机,用户或密码执行强力测试.Medusa和hy ...
- 034-openstack中虚拟机启动后主机名设置问题
openstack中虚拟机启动后主机名设置问题,在centos7中设置hostname后怎么都是原来的hostname,根本无效. 方法一: 在centos7中除了修改hosts文件和network文 ...