说起前后端分离,大家包括我自己都会想到:
当今流行的MVC不就是最标准的前后端分离吗?
说到这里,我不禁要反问,MVC真正的实现了前后端分离了吗?
无论是PHP的MVC框架TP还是JAVA的MVC框架SpringMVC,他们实现的前后端分离或许应该被叫做:一定程度上的逻辑和展示的分离
当然我们不能泯灭MVC带来的贡献,MVC的出现让写代码不再是一行写到底,他给我们带来了分层的概念,并在一定的程度上减少了三层间的纠缠。
但是,我们回忆一下当我们基于MVC写代码的时候,是不是有这样的情况:
这样的一个新闻列表(html+php)
<div class="news">
<?php
foreach($results as $item){
?>
<li class='news_item'><a href="<?php echo $item['url'];?>"><?php echo $item['title'];?></a></li>
<?php
}
?>
</div>
或则是:这样的一个分页(jsp)
<table>
<tr><th>名字</th><th>说明</th><th>图片预览</th></tr>
<c:forEach items="${data}" var="item">
<tr><td>${item.advertName}</td><td>${item.notes}</td><td><img src="${item.defPath}"/></td></tr>
</c:forEach>
</table>
<ul>
<li><a href='?nowPage=${nowPage-1}'>上一页</a></li>
<c:forEach varStatus="i" begin="1" end="${sumPage}"> <c:choose> <c:when test="${nowPage==i.count}">
<li class='disabled'>${i.count}</li>
</c:when>
<c:otherwise>
<li class='active'><a href='?nowPage=${i.count}'>${i.count}</a></li>
</c:otherwise>
</c:choose>
</c:forEach>
<li><a href='?nowPage=${nowPage+1}'>下一页</a></li>
</ul>
在这些个项目中我们的开发人员就是在view层不断的“挖坑”和不断的“填坑”,而且虽然我们用到MVC框架,但是我们并没有真正的实现前后端分离。
如何实现前台人员就写前台,后台人员只管后台,这是我一直在思考的问题。
无论是为了满足业务上的需求:比如,前端变化频繁,或者前端效果要求非常高/跨设备的兼容性要求很高的情况下
还是为了使技术团队更加精进所在领域,团队分工更加明确,能和需求更好对接(界面问题归前台,业务功能开发归后台)的角度来看,我觉得做好前后端分离,是团队建设的很重要的一部。
当然这也是在公司有一定经济基础的条件下,我也是一个实用主义者,提倡为了业务而技术,而不是为了技术而技术。
------------------------说了这么多,大多都是我个人开发中遇到的一些情况和问题,下面开始正题了----------------------
听闻淘宝引入Nodejs来实现了淘宝团队的前后端分离,下面就看看常见的做法和淘宝的做法,供大家思考
web架构的发展经历了(也可以说正在经历)从后端为主MVC应用时代---->基于Ajax的SAP应用时代---->以前端为主的MV*时代---->基于Nodejs的全栈时代
这个过程也是随着经济发展,人们对审美,性能要求不断提升而发展来的。
在各个时代前后端配合的方式也不一样,分别看一下:
后端为主MVC应用时代
在MVC架构中一般是前端人员写模板,给后台人员套用,这就是上面说的那种情况,前后台纠缠不清,到最后就是大家一起写了,前台后台一起大包干,根本没有分工了。
基于Ajax的SAP应用时代
随着2004年gmail的诞生,随后也诞生了Ajax,它的到来让SPA疯狂了一把,这个时代前后台分工还算是很明晰的,后台提供接口,前台来调用。
同时也带来了一大堆的问题,前端代码过于复杂,而且前台严重依赖后端接口,如果后端数据模型不稳定经常变化,那么前台开发人员就会很痛苦,所谓牵一发动全身。可维护性很差,而且代码难修改。
以前端为主的MV*时代
前几年出现了各种前端框架,有mvc的Backone,有MVVM的angularjs等。。。
这些框架总的原则是先按类型分层,比如 Templates、Controllers、Models,然后再在层内做切分,
这个时代的应用实现了前后端分离,前端工作在浏览器端,后端工作在服务端。清晰的分工,可以让开发并行,测试数据的模拟不难,前端可以本地开发。后端则可以专注于业务逻辑的处理,输出 RESTful 等接口。
但是,这种应用全是异步请求,对SEO不利,前后台都要写逻辑控制,而且无法复用前后台的代码,存在一定程度上的重复开发。URL的设计要严重依赖配合后端,无法自主决定。
基于Nodejs的全栈时代
随着 Node.js 的兴起,JavaScript 开始有能力运行在服务端。这也带来了全新的架构:
这种架构下,存在两个UI Layer层,即他们都负责前台的工作:
基于浏览器的UI layer处理浏览器层面的展示逻辑,通过CSS控制样式,js添加交互功能,HTML 的生成也可以放在这层。
基于Nodejs的UI layer处理路由,模板,获取数据,cookie等。通过路由,前端终于可以自主把控 URL Design,这样无论是单页面应用还是多页面应用,前端都可以自由调控。
这样一来,后端终于可以摆脱对展现的强关注,转而可以专心于业务逻辑层的开发。此时,web server上也是javascript代码,所以一定程度上“前后台”可以复用了,对于需要SEO的场景我们可以在服务端上进行渲染。
这样基本解决了MV*时代的一些弊病。
-------------------------------讲了这么多,我们看看淘宝到底是怎么利用Nodejs实现前后端分离的----------------------------
借一张网友的图:
看看网友的分析:
- 最上端是服务端,就是我们常说的后端。后端对于我们来说,就是一个接口的集合,服务端提供各种各样的接口供我们使用。因为有Node层,也不用局限是什么形式的服务。对于后端开发来说,他们只用关心业务代码的接口实现。
- 服务端下面是Node应用。
- Node应用中有一层Model Proxy与服务端进行通讯。这一层主要目前是抹平我们对不同接口的调用方式,封装一些view层需要的Model。
- Node层还能轻松实现原来vmcommon,tms(引用淘宝内容管理系统)等需求。
- Node层要使用什么框架由开发者自己决定。不过推荐使用express+xTemplate的组合,xTemplate能做到前后端公用。
- 怎么用Node大家自己决定,但是令人兴奋的是,我们终于可以使用Node轻松实现我们想要的输出方式:JSON/JSONP/RESTful/HTML/BigPipe/Comet/Socket/同步、异步,想怎么整就怎么整,完全根据你的场景决定。
- 浏览器层在我们这个架构中没有变化,也不希望因为引入Node改变你以前在浏览器中开发的认知。
- 引入Node,只是把本该就前端控制的部分交由前端掌控。
然后给了一个淘宝应用的例子:
淘宝宝贝详情页静态化之后,还是有不少需要实时获取的信息,比如物流、促销等等,因为这些信息在不同业务系统中,所以需要前端发送5,6个异步请求来回填这些内容。
有了NodeJS之后,前端可以在NodeJS中去代理这5个异步请求,还能很容易的做Bigpipe,这块的优化能让整个渲染效率提升很多。
可能在PC上你觉得发5,6个异步请求也没什么,但是在无线端,在客户手机上建立一个HTTP请求开销很大,有了这个优化,性能一下提升好几倍。
----------最后我们总结一下-------------------
前后端分离的目的:
前端:负责View和Controller层。更有甚者,引入Nodejs直接请求服务端,绕过后端数据处理。
后端:负责Model层,业务处理/数据等。
前后端分离的意义:
技术上,分工更专业
业务上,沟通更便利