基于Angular2的模块化Web应用架构设计
2019-01-30翁湦元单杏花朱建军王雪峰
翁湦元,单杏花,朱建军,王雪峰
(中国铁道科学研究院集团有限公司 电子计算技术研究所,北京 100081)
随着前端技术的飞速发展,如今的Web开发已不仅局限于HTML+CSS+javascript的传统开发模式。HTML5,ES6,ES2017等新技术标准陆续实施,Nodejs,TypeScript等新技术的推广与普及,前端开发正逐渐朝着标准化、规模化、模块化方向发展[1]。
Angular2是Google开发的前端框架与微软所推广的TypeScript相结合的产物,具有深厚的技术背景,是一个适合编写大型应用的框架[2]。通过编译为ES6标准的Javascript代码在客户端运行。Angular2引入了模块化、依赖注入、MVVM(Model-View-ViewModel)设计模式[3]等后端开发等理念,以完整工程的思想管理前端项目。同时Angular2将Web项目的包装为单一页面应用(SPA,Single Page Application,)的形式,减少了页面请求次数,使页面响应、切换更迅速,显著提升用户浏览体验。
本文以Angular2开发框架为基础,在开发实践的基础上进行总结,以保障应用安全、提高开发效率、提升用户体验为目的,分别从应用分层、应用安全和应用性能优化角度提出应用开发架构的关键设计和实现方法。
1 架构优势
1.1 MVVM设计模式
MVVM模式是传统MVC(Model-View-Controller)设计模式的进一步发展的产物。MVVM模式将原本数据、逻辑与页面一体的混合开发模式拆分为模型、视图两个层次进行开发,并由一个ViewModel将视图与模型进行双向绑定,View仅关心用户交互部分、响应ViewModel的事件;ViewModel负责封装业务逻辑,并把数据模型的变化传递给视图,从而达到松散耦合的效果,提高了开发效率[4]。MVVM设计模式如图1所示。
1.2 SPA应用
传统的Web应用将页面渲染工作由服务端完成,因此服务端在承担常规业务计算压力的同时也要承担页面渲染的计算压力,造成客户端页面响应缓慢,流量消耗大的问题[5]。
图1 MVVM设计模式示意图
SPA应用仅在用户第一次访问Web时获取完整的HTML以及静态资源文件,此后的用户交互均通过Ajax(Asynchronous Javascript And XML)请求的方式与服务器进行通信,服务器仅负责处理常规的业务计算,并以JSON(JavaScript Object Notation)格式响应。这样客户端仅需要根据数据更新局部页面,提高了响应性能、减少了大量不必要的数据传输。
1.3 依赖注入
Angular2参考了Java的Spring框架中的依赖注入概念,将对象之间的依赖关系由容器管理,以移除类之间的依赖。提高了代码的灵活性与可维护性。
2 应用架构设计和应用安全设计
在Angular2框架的基础上,对Web应用架构进一步设计,以达到提高开发效率、保障应用安全的目的。以下分别从应用架构设计以及应用安全设计两个方面进行阐述。
2.1 应用架构设计
2.1.1 基础结构
Angular2应用中基础模块和服务通过依赖注入方式进行管理,组成了应用的基本模型与逻辑层,由类似HTML风格编写的指令(Directive)形成模板(Template)结合组件(Component)通过双向绑定组成了模型视图层从而展现应用的内容,并根据指令响应用户的交互。Angular2的基础应用结构如图2所示。
图2 Angular2基础结构说明
2.1.2 应用分层
(1)基础层
应用基础层包含Angular2启动的必要代码,即:应用主程序、根模块、根路由以及根组件;同时应用底层的配置常量信息放置在应用基础层中。
(2)公共服务层
公共服务层将各业务模块及组件可以共同使用的公共函数代码封装为公共服务和工具类,并在应用启动时完成初始化,以供业务模块和组件进行调用。这些公共服务层代码与应用业务不直接相关。
(3)业务模块层
Angular2中视图与逻辑以及页面数据被封装为了组件(Component)。组件负责控制屏幕上的一小块视图区域。视图层的组件是Angular2应用与用户交互的基本功能单元。实际场景中一个应用往往包含众多组件,因此为有效管理各组件,使应用功能结构更为清晰,以“高内聚、低耦合”为原则,将功能相关的若干组件进行封装,变为独立的模块。每个功能模块均有各自的模块定义、路由管理、服务和组件。
通过业务模块划分,将分散的组件、服务归纳集中于各功能模块之内,从而将模块打造成自给自足的生态系统。合理设计的模块可以很方便地移植到其它应用当中而不需要代码修改,有利于代码的复用。同时,Angular2的模块化设计使得应用支持模块的动态加载机制,各模块按需加载,起到了加快应用启动速度、节省网络带宽以及保护代码安全的作用。
模块化应用架构分层设计如图3所示。
2.1.3 模块加载策略
基础层是应用启动的入口,为简化模块加载过程,保留一个业务模块,并将其组件、服务等部分分别命名为:Module,ModuleRoute,ModuleService,ModuleComponent。从应用启动到最终业务模块的加载流程如图4所示。
根模块(RootModule)启动后将载入根路由(RootRoutes)、公共服务层的公共服务(CommonServices),并载入和展示根组件(RootComponent)。同时,其余业务模块(Module)在Angular2默认的配置下会预先载入,业务模块内的路由(ModuleRoutes)、业务服务(ModuleService)以及模块内组件(ModuleComponent)均会在后台相继完成初始化动作。当用户在根组件中点击触发页面跳转时才会进入业务模块,并由业务模块的路由引导激活并展示相应的组件。
图3 模块化应用架构分层设计
图4 模块加载策略
2.2 应用安全设计
2.2.1 模块安全与组件安全
有别于传统Web应用,用户的访问权限控制可以在后端完成。由于前端项目的代码必须在客户端浏览器环境下执行,用户可以轻易获取前端项目的逻辑代码,因此安全措施是必须的。从图4可以看出,Angualr2默认将在应用启动时加载全部模块,需要采取一定的保护措施。以下将分别从模块载入和组件激活两方面进行阐述。
(1)模块安全
选取手术室急诊患者110例作为研究对象,根据护理方法将其分成两组。其中,对照组男28例,女25例,年龄34~72岁,平均年龄(53.85±4.72)岁;观察组男29例,女28例,年龄31~74岁,平均年龄(54.28±4.51)岁。两组患者的一般资料对比,差异无统计学意义(P>0.05)。
将应用按照业务进行模块化划分后,通过Angular2官方提供的CanLoad接口来控制模块的载入与否。对于用户无权访问的模块,将不被载入客户端,从而保护了模块代码的安全。
以上代码即为CanLoad接口的一种实现,若用户为已登录状态,则可以载入受保护的模块,否则无法载入。同时在载入模块的路由配置中加载该CanLoad接口的实现类。
以上代码通过对路由的CanLoad的参数注入,在业务模块加载前实现模块的安全保护。
(2)组件安全
对于已载入模块,用户若无权访问模块内部的组件,应用也不应予以展示。与模块安全保护类似,通过实现CanActivate接口控制组件的展示与否。
以上代码即为CanActivate接口的一种实现,若用户为已登录状态,则可以激活并展示相应组件,否则跳转至登录页面,待用户完成登录认证后再跳转回原页面。
上述代码通过对路由的CanActivate的参数注入,实现组件的保护。
综上所述,CanLoad通过权限设置使未授权代码不被载入用户终端,从而保护了代码安全;CanActivate通过权限设置使未授权代码不被激活执行,从而保证了应用安全。两者共同构成了Angular2应用层面的安全屏障。
通过Ajax请求与服务端交互是Angualr2应用的基本交互模式,服务端会对外暴露很多数据接口。因此,对数据接口的保护是必须的。服务端防护主要通过CSRF和Spring Security来完成[6]。
(1)CSRF防护
CSRF(Cross-site request forgery)是一种广泛存在的网站漏洞,通过隐式携带用户的登录信息从第三方网站发起恶意操作[7]。在同一会话中,通过在提交的数据中提供一个不可预测的随机数标识来确保提交数据的合法性,从而过滤了第三方网站的恶意数据,保证了只有真正访问Web应用的用户才有权限访问数据接口。该随机数标识被称为csrf-token。
(2)权限验证
CSRF防护仅能保证数据的合法性,但不能保证接口的操作权限得到有效控制,因此必须在后端服务上增加一套安全验证机制[8]。
现有Web应用的安全验证框架有很多,我们采用较为成熟的Spring Security进行说明[9]。Spring Security是Spring Framework基础上最成熟的安全系统[10],通过 IOC(Inversion of Control)和 AOP(Aspect Oriented Programming)机制实现了原项目的无侵入式快速部署,应用逻辑与安全逻辑的分离。
Spring Security的权限验证流程如图5所示。
图5 权限验证流程
2.2.3 应用安全设计小结
通过对模块安全、组件安全和后端接口安全的设计,最终达到了未授权模块禁止加载,未授权组件禁止显示,未授权接口禁止调用的效果。最大程度地保障了应用的代码与数据的安全。
3 应用性能优化
3.1 应用加载优化
(1)加速资源载入:通过nginx反向资源代理可以有效减轻Web服务端网络负载压力;通过CDN资源加速可有效加快用户从网络下载应用js/css静态资源的速度。
(2)缩短启动时间:通过启用Angular2应用生产环境编译选项可以有效缩小应用最终js文件的大小;开启AOT(Ahead-of-time)编译,可以有效提高应用在客户端的执行速度,缩短初始化时间。
3.2 应用响应优化
由于SPA应用已经最大限度缩短了页面切换的时间,因此进一步优化应用响应速度的空间在于加速数据接口的响应速度。通过有效利用HTML5的storage本地存储特性,可以将频繁查询的数据写入缓存。页面加载直接使用缓存数据,并在后台调用接口查询,仅在数据与缓存出现差异时再重绘界面。缓存优化流程如图6所示。
图6 缓存优化流程
由图6可以看出,在理想状况下若缓存命中,则页面数据直接从缓存获取,完全没有数据查询与加载的耗时,而即使数据与缓存出现差异,也只重绘数据变化的部分,最终页面的展示耗时与未加缓存的耗时相同。
4 结束语
本文以Angular2框架为基础,阐述了Angular2框架的优势,提出了模块化Web应用的架构设计,设计内容包括:(1)Angular2应用的基础结构;(2)将应用分为基础层、公共服务层、业务模块层3层架构,从而达到各模块代码解耦,提高开发效率的作用;(3)分别从模块、组件安全和服务安全角度说明了应用架构的安全设计,利用Angular2的组件加载机制实现了基于用户权限认证的组件加载,提高了应用运行的安全性;(4)通过AOT预编译机制和本地缓存机制优化了应用的加载速度和响应速度。通过以上设计可以有效保障应用安全、提高开发效率、提升用户体验。