本文作者为蚂蚁集团工程师王辰,主要介绍了他对于前后端分离架构模式的思考。
引子
最近在项目中遇到了前后端分离如何实现的问题,搞得有点[裂开了]。
其实这个问题并不新鲜,因为从这个世界上的研发被分为前端和后端两类的时候开始,大家就哭着吵着要分家了。
但是就像茴字有多种写法一样?分家有多少种方式?具体每种方式怎么操作?每种方式的优劣是什么?
本文试图结合最近的经验对这些问题作出总结。
而一旦说起前后端分离,始终绕不开的就是传统的MVC架构。
传统的单应用MVC架构
传统的MVC架构,如图所示:
特点:
●前端页面和后端部署在一起。
●一个域名:前后端使用相同的域名。
●登陆态通过cookie-session模式维护。(其中session可以放在db中,也可以放在分布式缓存中)
●spring框架天然支持:CookieHttpSessionStrategy
在大规模的软件工程中,由于前后端技能各自的专业化,前后端分离有其必要性,所以在传统的单应用MVC架构基础上,可以做如下前后端分离:
前后端分离-情况一:前后端同域名
示意图如下:
特点:
●前端页面和后端分离部署
●一个域名:前后端使用相同的域名
●登陆态通过cookie-session模式维护(因为同域名)
●spring框架天然支持:CookieHttpSessionStrategy
前后端分离-情况二:前后端不同域名
示意图如下:
特点:
●前端页面和后端分离部署
●前后端使用不同的域名
●此时不能继续使用cookie-session模式维护登陆态,需要使用tokenId-session的交互模式。
●spring框架天然支持:HeaderHttpSessionStrategy
存在的问题:
●前端跨域访问。
●前端跨域写入cookie。有些浏览器完全不支持跨域写入cookie,比如safari,这一点非常致命,尤其是在iphone上。
实践:项目中的“分裂”和“缝合”
在最近的项目中,我们就遇到了现状是情况一,但因为前端平台的限制(前端直接把研发工程部署到了生产域名),需要我们同时支持情况二的特殊情况。
这种情况同时要支持cookie(前端是PC)和tokenId(前端是H5)两种模式,目前spring框架无法直接支持。
调研和验证之后,我们后端的解决方案也非常简单粗暴:
1)向前端提供登陆接口(信任登陆),返回tokenId。
注:这里需要注意tokenId被盗用等安全性问题,这是另一个话题,本文不表。
2)直接修改CookieHttpSessionStrategy中的DefaultCookieSerializer,同时兼容cookie和tokenId模式,如下;
(当然,前端也得改,但是前端PC和H5本身就是两个端,本来就要改)。
可以看到,(情况一和情况二)都是在单应用mvc架构上的改造。
如果即要支持客户端、H5、小程序等各种端,那么一定不能使用mvc模式,更不能使用cookie-session这种仅在浏览器中支持的交互模式(何况有些浏览器都不支持跨域cookie),因此应该做完全的前后端分离。
完全前后端分离
完全的前后端分离中,前后端必然使用tokenId交互(比如Oauth),后端应以网关的模式提供所有的服务,同时登陆态的管理也应该交由独立的登陆系统。
示意图如下:
特点:
●前端页面和后端分离部署
●前后端使用不同的域名
●使用tokenId-后端登陆态管理(如Oauth等方式)。
如何选型?
那么,这四种模式该如何选型呢?我的想法如下:
传统MVC模式
真正意义上的全栈开发,适合只在单一客户端上开发,一个人或者几个人的创业团队。
前后端分离(情况一)
不推荐这种模式,使用这种方式还不如一步跳到前后端分离(情况二)。
前后端分离(情况二)
适合曾经是单应用的传统MVC模式,现在想做前后端分离,但是又没有太多经验的团队,又不想步子迈得太大。
完全前后端分离
适合有一定前后端分离的经验,一开始就定位为需要支持多端的大型团队,这样的团队者规模比较大、团队中的每个小组负责一个模块或者一个领域。
一般的演进路径:传统MVC模式 -> 前后端分离(情况二)-> 完全前后端分离
总结
前后端分离是生产技能精细化带来的分工导致的必然结果,是优化前后端生产关系的一种方法。
这种分工方法和全栈开发有一定的矛盾性。
实践中,我们应该按照自己的实际情况和目标来选型,而不是盲目追求新概念和新技术。