前后端分离已成为互联网项目开发的业界标准使用方式,通过Nginx+Tomcat的方式(也可以中间加一个NodeJS)有效地对前端和后端的开发进行解耦。并且前后端分离会为以后的大型分布式架构、弹性计算架构、微服务架构、多端化服务(各种客户端,比如浏览器、车载终端、安卓、IOS等)打下坚实的基础。前后端分离的核心思想就是前端HTML页面通过AJAX调用后端的RESTFUL API接口,并通过JSON数据进行交互。

前端的开发与后端的开发分离

以前的JavaWeb项目,大多数都是Java程序员又搞前端,又搞后端。而随着时代的发展,渐渐的许多大中小公司开始把前后端的界限分得越来越明确,即前端工程师只管前端的开发,后端工程师只管后端的开发。大中型公司需要专业的人才,小公司需要全才(省钱)。但是对于个人职业发展来说,还是分开比较好,因为当生涯发展到后期的时候,企业往往要的是在某一方面上的专家,而不是熟练工。如果一个人前端后端都会一点,那也可以说什么都不会。

前端追求的是页面的表现、速度的流畅、兼容性和用户的体验等。因此对于前端开发工程师来说,需要把精力放在HTML5、CSS3、JavaScript、jQuery、AngularJS、BootStrap、ReactJS、VueJS、Webpack、Less/Sass、Gulp、NodeJS、Google V8引擎、JS多线程、JS模块化、JS面向切面编程、设计模式、浏览器兼容性、性能优化等上。

后端追求的是三高(高并发、高可用、高性能)、安全、存储、业务等。因此对于后端开发工程师来说,需要把精力放在Java基础、设计模式、JVM原理、Spring全家桶的原理及源码、Linux、关系型数据库事务隔离和锁机制、MongoDB、HTTP/TCP、多线程、分布式架构、弹性计算架构、微服务架构、Java性能优化、数据库性能优化以及相关的项目管理等等。

往某个方向深深钻研,这样你的核心竞争力才会越来越高。正所谓你往生活中投入什么,生活就会反馈给你什么。千万别勉强自己去追求所谓的全栈,因为不管是前端和后端,到后期都有很多高深的东西让你花费所有精力,你想什么都会,最后可能什么都不会(太贪心的人最后什么都得不到,别信圣诞老人说的那句我全都要)。当然也不是说就不能去学,学也是可以的,但是要偏重点,分清主次,就像人生不要把时间浪费在不值得的人和物身上一样。

前后端分离解决的耦合问题

曾几何时,我们的JavaWeb项目都是使用了若干个后台框架,比如Spring MVC、Structs、Spring Boot、Spring JDBC、Hibernate、MyBatis等。大多数项目在Java后端都是分了三层,即控制层(Controller)、业务层(Service)和持久层(Dao)。控制层负责接收参数,调用相关业务层,封装数据,以及路由和渲染到JSP页面(或模板页面,如Freemarker)。然后JSP页面上使用各种标签或者手写Java表达式将后台的数据展现出来,玩的就是MVC那套思路。

我们先看这种情况:我们开发一个网站,需求定完了,代码写完了,测试跑完了,用Maven或IDE等工具把代码打成一个war包完了,把war包发布到生产环境下的WEB容器完了,启动WEB容器完了,域名、DNS配置完了,网站就可以访问了。这时候,我们的前后端代码全都在那个war包里了,包括JS、CSS、图片等各种静态资源文件。

接下来,我们在浏览器中输入网站域名(www.xxx.com),浏览器在通过域名和DNS服务器找到我们的服务器外网IP,将HTTP请求发送到你的服务器,在TCP三次握手之后(HTTP下面是TCP/IP),通过TCP协议开始传输数据,我们的服务器得到请求后,开始提供服务,接收参数,之后返回我们的应答给浏览器,浏览器再通过Content-type来解析返回的内容,呈现给用户。

这里我们假设我们的首页中有100张图片,那么当用户访问首页的时候,就需要建立100个HTTP请求,我们的服务器接收这些请求,都需要耗费内存去创建Socket来玩TCP传输(消耗服务器上的计算资源)。重点来了,这样的话,我们的服务器的压力就会非常大,因为页面中的所有请求都是只请求到我们的这台服务器上,如果一个人还好,如果是有10000个人并发访问呢(这里先不说服务器集群,就说单实例服务器),那么我们的服务器恐怕扛不住(TCP连接、带宽、内存、硬盘、IO、WEB服务器的内存等方面),恐怕会宕机。

这就是为什么大中型的WEB应用要解耦的原因。理论上我们是可以把数据库、应用服务、消息队列、缓存、用户上传的文件、日志等都丢在一台服务器上,也不用玩什么服务治理,也不用做什么性能监测,什么报警机制等,爱宕机就宕机好了(佛系青年)。可是现实不允许我们宕机啊,当某个子应用因为内存不稳定而导致整个服务器内存溢出,再而导致我们的网站挂掉的时候,我们就糟糕了。比如我们公司的业务如果这时候正好处于井喷式发展的高峰期的时候,服务器挂掉了,业务就被技术卡住了,那么就可能会导致大量用户的流失,后果不堪设想。这里顺便提一句,技术一定要走在业务前面,否则可能会错过最佳的发展期。

另外的,当你的应用全都耦合在一起,就相当于一块巨石,当服务器负载能力不足时,一般会使用负载均衡的方式,将服务器做成集群。这样其实你是在水平扩展一块块巨石,性能加速度会越来越低。要知道,本身负载就低的功能或模块是没有必要水平扩展的,水平扩展要针对性能瓶颈去扩展才对。在这里的例子中,性能瓶颈跟前端没有关系,没有必要去水平扩展前端。同时,发版部署的时候,如果只是改了后端的代码,却要前端代码也跟着重新发布,显然也降低了效率。

正因为这样,正常的互联网架构都是把WEB服务器集群、应用服务器集群、文件服务器集群、数据库服务器集群、消息队列集群、缓存集群等集群拆分开的。

前后端耦合的缺点(以JSP为例)

以前的JavaWeb项目大多数使用JSP作为页面层展示数据给用户,因为流量不高,因此也没有那么苛刻的性能要求,但现在是大数据时代,对于互联网项目的性能要求是越来越高,因此原始的前后端耦合在一起的架构模式已经逐渐不能满足我们,因此我们需要找到一种解耦的方式,以大幅提升我们的负载能力。前后端耦合主要有以下的缺点(以JSP为例):

1.动态资源和静态资源全部耦合在一起,服务器压力大,因为服务器会收到各种HTTP请求,例如CSS的HTTP请求,JS的,图片的等等。一旦服务器出现状况,前后台一起完犊子,用户体验极差。如果前后端分离,你后端的服务器挂了,前端服务器没挂,用户仍然可以看到界面,虽然请求不到数据,嘿嘿。

2.UI出好设计图之后,前端开发工程师只负责将设计图切成HTML,需要由Java开发工程师来将HTML套成JSP页面,出错率较高(因为页面中经常会出现大量的JS代码),修改问题的时候需要双方协同开发,效率低下。

3.JSP页面必须要在支持Java的WEB服务器上运行(如Tomcat、Jetty、Resin等),无法使用Nginx等(官方宣称单实例HTTP并发高达5W),性能提升不上来。

4.第一次请求JSP,必须要在WEB服务器中编译成Servlet,第一次运行会较慢。然后之后的每次请求JSP都是访问Servlet再用输出流输出的HTML页面,效率没有直接使用HTML高(注意是每次噢)。

5.JSP内有较多内置的专属标签和表达式,前端开发工程师在修改页面时往往会挠头挠到秃头。

6.如果JSP中的内容很多,页面响应会很慢,因为是同步加载,一次输出所有内容。

7.修改JSP页面需要前端开发工程师使用Java的IDE以及配置各种后端的开发环境,对前端开发工程师极不友好。

前后端分离的优点

1.前后端分离可以真正地实现前后端解耦,前端服务器使用Nginx。前端/WEB服务器放的是CSS、JS和图片等一系列静态资源(甚至可以把这些静态资源放到特定的文件服务器,如阿里云的OSS,并使用CDN加速)。前端服务器负责控制页面引用、跳转和路由,前端页面通过AJAX异步调用后端的接口,后端/应用服务器使用Tomcat(把风花雪月交给前端,只提供数据),加快整体响应数据。(这里需要使用一些前端工程化的框架,如NodeJS、React、Router、Reudx、Webpack等)

2.前后端分离的模式下,如果发现Bug,可以快速定位是谁的问题,不会出现互相踢皮球的现象。如果是页面逻辑、跳转错误、浏览器兼容性问题、脚本错误、页面样式等问题,通通是前端开发工程师的锅。如果是接口数据出错、数据提交失败、应答超时等问题,则后端开发工程师应该挺身接锅。双方职责分明,就不会打架。

3.前后端分离在大并发的情况下,我们可以同时水平扩展前后端服务器。要知道淘宝的一个首页就需要2000+台前端服务器做集群来抗住日均多少亿的日均PV。(阿里的技术峰会说到他们的WEB容器都是自己写的,就算单实例抗10万HTTP并发,2000台是2亿HTTP并发,并且他们还可以根据预知洪峰来无限扩展,好恐怖啊,就一个首页。。)

4.前后端分离可以减少后端服务器的并发/负载压力。除了接口以外的其他所有HTTP请求全部转移到前端Nginx上,接口的请求则转发调用Tomcat。且除了第一次页面请求外,浏览器会大量调用本地缓存去缓存页面。

5.前后端分离的模式下,即使后端服务器暂时超时或宕机了,前端页面也会正常访问,只不过数据刷不出来而已。

6.前后端分离的模式下,后台的接口可以复用。比如需要做微信相关的轻应用,接口就完全可以共用,再比如说APP相关的服务,也可以只通过一些代码重构,就可以大量复用接口,提升开发效率。(多端应用)

7.页面显示再多的内容也不怕了,因为从同步加载改成了异步加载。

8.Nginx支持页面的热部署,不用重启服务器,前端升级更无缝。

9.增加代码的维护性和易读性,提高开发效率(前后端代码耦合在一起很难读,比如JSP页面)。

10.前后端可以并行开发,提高开发效率。

11.在Nginx中部署证书,外网使用HTTPS访问,并且只开放443和80端口,其他端口一律关闭(防止黑客端口扫描),内网使用HTTP,性能和安全都有保障。

前后端分离的注意事项

1.在开需求会议的时候,前后端工程师必须全部参加,并且需要制定好接口文档,后端工程师要写好测试用例(2个维度),不要让前端工程师充当你的专职测试。

2.上述的接口并不是Java里的Interface,说白了调用接口就是调用你Controller里面的方法。

3.我们需要一些前端的框架来解决类似于页面嵌套,分页,页面跳转控制等功能。

4.小项目的话,比如单纯的内网项目,就没有必要前后端分离了,复杂架构反而会拖累性能。但是如果是大型外网项目,前后端分离就非常必要了。

5.以前还有人用类似于Velocity/Freemarker等框架模板生成静态页面,个人觉得和使用JSP其实也相差不远,也就是性能好一点,没有实现真正的前后端分离。

6.前后端分离会加重前端团队的工作量,减轻后端团队的工作量,提高了性能和可扩展性。

7.如果页面上有一些权限等等相关的校验,这些相关的和数据也可以通过AJAX从接口里拿。

8.对于既可以前端做又可以后端做的逻辑,建议放在前端,因为逻辑计算时需要计算资源的,如果放到后端去运行逻辑,则会消耗带宽、内存和CPU等等计算资源。你要记住一点就是服务端的计算资源是有限的,而如果放到前端,使用的是客户端的计算资源,这样你的服务端负载就会下降(高并发场景)。类似于数据校验这种,前后端都需要做。

9.前端需要有机制应对后端请求超时以及后端服务宕机的情况,友好地展示给客户。

前后端分离的扩展阅读

1.对于JS、CSS、图片这类静态资源可以考虑放到类似于阿里云的OSS这类文件服务器上(如果是普通的服务器和操作系统,存储在到达PB级(1000TB)的文件后,或者单个文件夹内的文件数量达到3-5万,IO会有很严重的性能问题),再在OSS上配CDN(全国子节点加速),这样你页面打开的速度像飞一样,无论你在全国的哪个地方,并且你的Nginx的负载会进一步降低。

2.如果你要玩轻量级微服务架构,要使用NodeJS做网关,用NodeJS的好处还有利于SEO优化,因为Nginx只是向浏览器返回页面静态资源,而国内的搜索引擎爬虫只会抓取静态数据,不会解析页面中的JS,这使得应用得不到良好的搜索引擎支持。同时因为Nginx不会进行页面的组装渲染,需要把静态页面返回到浏览器,然后完成渲染工作,加重了浏览器的渲染负担。浏览器发起的请求经过Nginx进行分发,URL请求统一分发到NodeJS,在NodeJS中进行页面组装渲染;API请求则直接发送到后端服务器,完成响应。

3.如果遇到跨域问题,Spring4的CORS可以完美解决。但一般使用Nginx做反向代理的都不会有跨域问题,除非你把前端服务和后端服务分成两个域名。JSONP的方式也被淘汰掉了。

4.如果想玩多端应用,主要要去掉Tomcat原生的session机制。要使用token机制,使用缓存(因为是分布式系统),做单点。关于token机制的安全性问题,可以了解下JWT(JSON Web Token)。

5.前端项目中可以加入mock测试(构造虚拟测试对象来模拟后端,可以独立开发和测试),后端则需要有详细的测试用例,保证服务的可用性和稳定性。

总结

前后端分离并非仅仅是一种开发模式,而是一种架构模式(前后端分离架构)。千万不要以为只有在写代码的时候把前端和后端分开就是前后端分离了,这样的理解太片面了。前后端分离是需要区分前后端项目的,即前端项目和后端项目是两个项目,放在两个不同的服务器,需要独立部署,两个不同的工程,两个不同的代码库,两组不同的开发人员。前后端开发工程师需要约定交互的接口,实现并行开发。而在开发结束之后,前端项目和后端项目都需要进行独立部署,前端通过AJAX来调用HTTP请求,调用后端的RESTFUL API。前端只需要关注页面的样式与动态数据的解析和渲染,不用关心数据是怎么产生的;后端则专注于具体的业务逻辑,返回前端展现所需要的业务数据即可。

 

"无论去哪里,都不要失去重新开始的勇气。"

你要去做一个大人,不要回头,不要难过。
posted on 2020-02-19 13:50  龙-OSCAR  阅读(487)  评论(0编辑  收藏  举报