摘要
本文首先分析了Web应用开发架构之经典的MVC模式在服务端资源占用和用户访问网页的体验两方面的不足,提出了前后端分离的架构设计,从前后端分离架构风格的交互协议和特点、前端进一步分离并接管控制路由、前后端开发前的接口约定等几个方面进行了阐述,最后对该架构风格的应用场景做了总结。
Web之MVC架构
传统Web应用开发架构经历了从视图和业务逻辑完全混在一起的单体应用发展到视图和业务逻辑分离的MVC结构。最大的优点就是层与层之间实现了解耦,业务逻辑、跳转控制、视图展示各司其职。
1 MVC模式缺点
在MVC模式中控制器非常重要,是模型和视图进行沟通的桥梁,简单来说模型其实就是一个实体类对象,视图就是诸如JSP、HTML等页面模板,而请求首先到达控制器,控制器请求项目核心业务获取数据封装到模型对象,最后将模型传递到视图中进行展现。
这个模式有两个缺点:
1、用户每次想要看到最终页面必须要经过控制器、模型、视图三层
2、视图到达浏览器之前的所有渲染工作都在后端服务器进行,占用了服务器运算资源,同时页面性能无法得到很好的优化。
为了提高用户的流畅上网体验,同时防止高并发对服务器造成资源占用,应将页面渲染工作从后端服务器转移到前端进行,后台只负责提供数据,前端负责解析数据和页面渲染,这种架构就是前后端分离架构。
2 MVC模式中引入Ajax
将视图页面中的动态数据全部交给ajax发送请求到服务器,服务器返回json格式的数据,视图页面进行数据解析和界面渲染,这样就会让view负责数据展现和渲染,减轻了服务端压力和资源占用,提供更好的用户体验。改造后结构如下图所示:
这其实就是前后端分离的初步构想,简化后就是前后端分离模式。
前后端分离架构
假如把浏览器页面作为前端,其他提供数据的都作为后端的话,可以简化为如下所示前后端分离模式:
图2 前后端分离架构示意图
前后端之间通过RESTFUL风格的url发出ajax请求。REST (Representational State Transfer) 即表述性状态传递[1],它的核心思想是将互联网资源对应到一个url[2]上,对资源的相关操作分别用HTTP协议里的GET,POST,DELETE,PUT表示[3]。RESTFUL[4]既简单又直观,通过HTTP[5]的方法对资源进行操作,简化了客户端和服务器之间交流的表达。 RESTFUL风格的请求样例如下所示:
跨域解决方案
前后端通过ajax访问还有一个问题就是跨域,因为ajax的xhr对象是不允许跨域访问的,要解决跨域问题可以采用以下解决方案:
1、JSONP
基本原理就是通过动态创建script标签,然后利用src属性进行跨域,但是要注意JSONP只支持GET请求,不支持POST请求。
2、CORS(跨域资源共享)
利用nginx或者php、java等后端语言设置允许跨域请求
header('Access-Control-Allow-Origin:*');//允许所有来源访问
header('Access-Control-Allow-Method:POST,GET');//允许访问的方式
3、直接使用nginx服务器来部署前端项目,前端页面ajax请求的url直接指向nginx服务器的地址,由nginx反向代理指向后端服务器即可,这种方式是相对来说最佳解决跨域的方案。
前端进一步分离
从项目部署的角度来看,前后端彻底分离,需要为前端静态资源(html、css、图片等)配置一台服务器,负责页面跳转路由等,后端配置一台服务器,负责数据提供,前端异步调用后端提供的接口,并获得数据,这样加快整体响应速度。
传统前后端分离架构,后端还是有控制层负责转发请求,获取业务逻辑处理结果。而请求跳转本应该属于前端的操作,所以目前比较流行的前端框架比如React、Vue、Angular等均支持控制路由跳转的功能,这样后端就不需要控制器进行跳转,纯粹执行业务逻辑即可,这样的前后端分离是最为彻底的。
前端框架如VUE等框架技术采用的架构准确来讲是MVVM模式,该模式是工程师在解决WPF应用程序开发复杂度时提出的解决方案,它实现了View和Model的自动同步,开发者不需要再手动的绑定输入监听和手动的将数据结果展示在View上,这就是双向数据绑定的优势,这是其与传统MVC模式最大的不同。其架构模式如下图所示:
ViewModel解决了View和Model之间转换的开发效率问题。但是ViewModel内部的复杂度又变成了新的问题,其中一个问题就是双向数据绑定劣势。在双向数据绑定中,Model(可以理解为状态的集合) 中可以修改自己或其他Model的状态,用户的操作(如在输入框中输入内容)也可以修改状态。这使的改变一个状态有可能会触发一连串的状态的变化,最后很难预测最终的状态是什么样的。使得代码变得很难调试。
为了解决这个问题便有了后来的Vue单向数据流的解决方案-Vuex。在复杂度较高的业务上使用单向数据流来解耦View和Model的关系。
前后端的分工和交互
前后端分离之后,后端工程师专注与业务逻辑代码和数据库访问代码,不需要了解前端框架和技术,同样,前端开发人员也不需要学习后台编程,专注于前端框架和页面开发即可,这样分工可以让软件开发分工明确,团队成员做自己擅长的事情。在某个功能模块出现问题的时候,可以准确定位是谁的问题,避免出现代码堆在一起时互相指责的问题。
当然,前后端肯定是需要交互的,即前端工程师如何通过url调用后端开发人员提供的数据。项目开发初期需要前后端工程师协商形成一套标准的接口,即调用的API,其中的接口方法的访问路径、参数、类型等需达成一致。这套接口后续可以修改,但尽量不要做过多改动。形成API文档可以在项目中集成swagger2来构建RESTFUL API文档,通过在访问接口上直接添加注释就能实现。
方案评估
任何软件架构风格都不可能适合所有场景,前后端分离也不例外。如果我们项目符合以下情景,可以考虑采用前后端分离架构:
1、团队成员不是全栈工程师,大部分都擅长前端或者后台之一。
2、对网页性能和用户体验要求较高,尤其是展示类网站和移动APP。
3、高并发访问造成服务器压力过大,适合前端资源和后台逻辑部署到不同服务器上,减少对服务器直接访问量。