在现在的软件架构中,前后端分离是很普遍的软件架构,让前端更加专注于UI逻辑渲染,后台专注于数据业务逻辑,而前后端数据交互的方式就是通过API接口。
最早接触前后端分离的概念是在Gmail盛行的2006年年底(暴露年龄了),那时候的Gmail账号是需要邀请才有资格注册,你是否还记得邀请你的那个他吗?
Gmail盛行的原因,个人觉得是因为Gmail的用户体验是如此顺手、方便,也开启了Javascript+Ajax技术的发展之路,同时也出现了RIA(Rich Internet Application )的概念,即富网络应用,出现了很多技术人员去研究和模仿其实现。
对于我来说,同样被Gmail的体验吸引了,从那开始学习DIV+CSS布局,并对asp.net的网站管理后台进行重构,完成前后端分离,使其界面主题与数据服务分离,让前端(当时应该还没这个岗位)更加专注交互体验和主题界面,后端专注数据存储及逻辑。后来C#还推出了LINQ数据库访问技术,重构后的管理系统后台架构采用.NET 3.0+ASP.NET AJAX+LINQ
,前端架构采用Jquery为基础,ExtJS为UI组件框架。
期间前后端通讯规范,即API规范,是开发团队协商定义统一的数据交互标准,关于API规范后面再来谈。回归主题,先来谈谈为什么需要前后端分离?
为什么要前后端分离?
最直观的感受就是后端工程师对于数据的视觉呈现并不敢兴趣,在他们看来数据正确性比视觉效果更加重要,当然这只是个人觉得的原因之一。
其实最重要的原因是让数据逻辑和UI逻辑解耦,其实熟悉《CSS禅意花园》的朋友更容易理解,随着RIA的发展,UI逻辑相比之前变得更加丰富,需要适配的设备也越来越多,应用的数据逻辑并不会随着设备的不同而有大的变化,这个时候就需要更加专注UI逻辑的工程师。
最后就是性能及部署,在网络环境不好的年代,大型应用为了保证加载速度,一般都会采用CDN对静态资源进行加速,而CDN技术只是对静态资源(js、图片、css、html、视频、音频等)进行分发,对于动态计算数据逻辑是无法进行调度的。为了能够保证应用性能就必须采用前后端分离。
总结一下前后端分离的优化:
- 分工明确,让不同专长的人更加专注,提高工作效率及质量
- 实现应用高内聚低耦合,减少后端(应用)服务器的并发/负载压力。
- 可以使后台能更好的追求高并发、高可用、高性能,对于容器化部署可以达到更佳的动态扩展能力。
下面先来谈谈前后端分离架构里面设计的数据通讯基础API规范,比较常见的API规范有:RPC、RESTFul、GraphQL。
RPC
RPC的全称是
Remote Procedure Call
,即远程过程调用,与之对应的是本地过程调用,核心思想是把远程的方法映射到API。就是客户端基于某种传输协议通过网络向服务提供端请求服务处理,然后获取返回数据;而这种调用对于客户端而言,和调用本地服务一样方便,开发人员不需要了解具体底层网络传输协议。
为了方面大家理解什么是RPC,先通过简单的代码来看看本地过程调用是怎样的。
const numA = 1001; const numB = 1002; const addition = (a, b) => { return numA + numB; }; const total = addition(numA + numB);
调用addition
就是一个本地过程调用。通俗来讲就是调用本地代码中的提供的API方法的过程,就称为本地过程调用。
远程过程调用,最终调用的API方法不是运行在本地的,这个提供服务的程序有可能是运行在不同进程,甚至是不同机器上的或云主机上。RPC的调用过程从代码上来看,和调用本地的代码是非常相似,但具体的方法实现逻辑是在另外的进程或者主机上。下面是一段PHP中RPC调用的代码片段,调用的方法addition
就是在远程主机上实现具体的逻辑。
$numA = 1001; $numB = 1002; $api="https://rpc.devpoint.cn/"; $rpcHelper = new \HproseHttpClient($api); $total = $rpcHelper -> addition($numA,$numB);
从调用来看,本地调用和RPC调用没啥区别,就是在架构上有所不同,相对来说RPC调用一般都是异步的。
RPC是通过约定协议来实现跨端通信的,调用双方遵守同一套协议,客户端会通过协议把需要调用的服务告诉服务端,服务端接收到客户端信息后进行逻辑运算后,再通过协议把结果回传回给客户端。在业内比较知名的RPC框架是Google公司的grpc,grpc是使用ProtoBuf(接口描述语言Interface Definition Language,IDL)定义双方的通信协议的。
RESTFul
REST 是目前比较流行的一种API设计理论。因为它结构清晰、符合标准、易于理解、扩展方便,所以被越来越多的应用场景所使用。REST(REpresentational State Transfer),首次出现在 2000 年 Roy Thomas Fielding 的博士论文中,它指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是 REST 的。
接下来就是RESTFul规范,之前在《REST介绍与设计指南》简单介绍过,应该是目前前端和后端数据通讯应用比较广泛的。
在RESTFul架构下,客户端会通过URI来确定需要请求的资源,建立连接后,会通过HTTP来发送/接收数据。客户端的请求目标通过统一接口访问的是资源(Resource),而不是服务本身。
GraphQL
GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。
从定义来看,GraphQL的主要功能是让客户端可以根据业务场景需要定义自己想要查询的数据,一般随着API数量的增加,客户端实现不同业务场景需求时就可以像堆积木一样组装业务需要的API,进而提高API的重复利用率。如有兴趣,可以看看《NodeJs中使用Apollo Server构建GraphQL API服务》的实例,或许对你有所启发。
前后端分离架构
前后端分离架构,可以让前后端更加专注,提高项目开发效率。在架构中比较关键的是API通讯规范的制定,好的规范确实可以让效率提高。在架构中定义好了API通讯规范,前端按照规范MOCK数据推进项目,后端按照规范输出相应的API,可以大大缩短联调的时间。至于使用何种API规范,应该根据团队的情况来制定。
下面是简单的开发架构图:
下面是比较普遍的前后端架构图:
在微服务、serverless、容器技术成熟的今天,前后端分离对于性能及运营的提升相当明显,下面是容器化部署的架构图,可以快速实现前后端版本更新、扩展。
总结
本文简单介绍了前后端分离的优势,数据通讯API规范,列举了常见的应用架构图和容器化部署架构图。在具体实施过程中还涉及API文档管理、协议管理测试等问题,需要根据团队情况做出相应调整,需要结合实际不断去思考总结一套最符合团队的架构。