hello~亲爱的看官老爷们大家好~有一段时间没写文章了,最近忙于为一个对内的数据可视化平台进行完全的前后端分离。原来的项目是一个基于 Vue
的单页应用,重构后接入 Node
作为中间层,达到完全的前后端分离。
由于项目相对简单,成本并不是太高。下文将简单介绍一下使用的技术栈与分离后的收益,重点是对基于 Node
做前后端分离的一点思考。
背景
大约是去年11月底入职新东家,接手一个仅 对内 的数据分析系统。新入职当然是希望做出点成绩,在更改部分 UI 与优化部分功能之后,发现页面性能还是比较低。排查后发现获取数据的接口没有缓存,也不是基于 RESTful
的,浏览器缓存完全不起作用。期间也经历了后端修改接口,前端代码大面积修改的情况。
基于后端同学不熟悉前端机制,我也抱着方便日后搞事情的心态,在多次滚地板之后,部门 Leader 同意接入 Node
作为中间层。
技术选型
在确定接入 Node
后,首先要做的就是技术选型。Node
一般就是在 Epress
、Koa
与 Egg
中选。在中间件的使用上,个人偏好 Koa
的形式,因而只好和 Express
说再见了。Egg是在
Koa` 上作了强约束,规定代码编写、目录结构等。
选型时我与前端 Leader 讨论了无数次,他认为 Egg
约束太多,扩展性较差,如若出现框架底层的 Bug 则难于处理,因而偏向于使用 Koa
。这样的顾虑十分合理,然而对于现在的项目而言,不太可能有功能会超出 Egg
所提供的,反而 Egg
所提供的功能能为项目搭建与维护减少不少的成本。至于约束,个人认为这反而是一件好事,一定程度上解决了多人开发时代码的组织问题。
考虑再三后,决定使用 Egg
作为 Node
的框架。
分离收益
由于项目不算十分复杂,接入的过程算是波澜不惊。唯一的麻烦是工期比较紧,因而分两步走:一期先接入 Node
,所有页端请求原样转发 Java
,返回的结果原样转发页端。二期对数据获取的接口进行整合与优化以提升性能。完成后收益还是客观的,贴两张图展示下成果。
原来某页面的性能(所有请求都是 Post 的):
接入 Node
相同页面的性能(转为方法为 Get):
可以看到,不论是数据下载量还是响应时间等指标,耗时均有降低。当然,这是建立在接入 Node
后我对接口进行了整合与缓存优化等措施后的对比。如果都是首次访问,公司内网 WiFi 环境下与原来的性能会有稍差一点,整体加载时间略高于 Java
直出50ms不到。也用过 Chrome 模拟弱网环境,耗时与 Java
直出基本一致。
而且开发体验上也比之前舒服得多,算是达到了接入 Node
前定下的目标:接入后在支持相同功能的情况下性能提高30%;在相同的开发时间内,完成相同的需求,但有更好的开发体验及更好的页端性能。
小结一下,前端的一切优化都是在模板与获取模板所需数据上进行优化,使用 Angular
、React
与 Vue
等框架构筑的单页应用,解决了模板的问题,可以不再让后端去动我们的模板。但是获取所需数据仍依赖于后端,不少单页应用交互上已经足够复杂,如果还需维护一套复杂的获取与整合数据的逻辑,还是十分头疼的。因而多接入一层 Node
处理数据的获取与整合,尽最大努力去优化页端的请求接口,让页端专注于交互,在条件成熟的情况下,是十分值得的。
思考
如若就为了推广 Node
,本文应该是把上面的步骤写详细,小结完就该结束了,这和很多大佬的实践文章一致(当然我写得不够好~)。然而和两位 Leader 的讨论过程中,感谢他们对 Node
技术抱有怀疑,提出了不少有意思的问题,结合我自己的思考,整理成提问形式呈现给大家。
为何接入
Node
作为中间层,和公司现行的PHP
有何区别?
没有区别!事实说,Node
能做的 PHP
一样能做。那么问题就转换为 Node
的意义是什么,为何摈弃公司相对成熟的 PHP
方案而转向 Node
?
我认为后端服务主要是稳定为主,业务调整不会特别频繁。而对于前端而言,业务频繁调整简直司空见惯,如果前后端耦合在一起,频繁让后端发版不是可取之策。同时,前后端对数据结构的要求及对其控制的粒度也大不相同。写得好 PHP
的同学不一定写得好前端,写得好前端的同学不一定写得好 PHP
。对于专业的领域,还是应该由专业的人去做,让前端控制整个模板及模板依赖的数据,对提高项目质量有很大的帮助。说句玩笑话,后端就搞搞数据库,吐吐 json
就好,前端就拿一下数据,切切页面就好。
进一步而言,前端若要接入 SSR
之类的功能,Node
还真比 PHP
有优势得多,也算是为日后搞事情做铺垫吧。
接入
Node
后性能会有多大提高?
不一定有提高,甚至有下降。此问题是我一期完成之后,测试页端性能时发现的。测试时,Node
除了将所有的需求原样转发外,还加了协商缓存,然而响应时间却更慢了。
接入前(为 Post 请求):
接入后(为 Get 请求):
正常来说,获取 10k 左右的数据时,协商缓存如若命中即返回 304,省略了下载的过程,理应更快的。通过打点,发现 Node
转发请求耗时额外增加 10ms 左右,然而在全公司内网 WiFi 环境下,整体下载时间不到 160ms。
因而引入 Node
不一定会有性能的提高,反而会因为多引入一层,而导致性能耗损。在对内的项目中或性能尚可的项目中,提高性能不足以成为接入 Node
的关键理由。换句话说,接入 Node
之后,在优化页端请求之前,并不可能为应用性能带来飞跃。
这个问题也算是我对 Node
态度转变的起点,开始从无脑支持接入 Node
到辩证地推敲,也引出之后的的问题。
接入
Node
有什么弊端?
前端的能力越强,意味着责任越多。例如之前可能是 Java
做的安全防护,可能就会下沉到 Node
端,这对大多数前端同学而已都是比较陌生的领域。
投入的成本与产出也是值得商榷的事情,毕竟 Node
再贴近前端,也始终是属于后端的领域。前后端思想不太一样,用前端的思维写后端,很可能写出十分糟糕的代码,轻则影响性能,重则内存泄漏。接入 Node
层后它反而成为拖累,相信大家也不愿看见。
毕竟 Node
对于不少公司而言是比较新的领域。尽管可能知道接入 Node
好处不少,但如何接入,接入后它能做什么,大家可能比较模糊。如何花最少的代价,平滑地接入 Node
的同时,最大限度的复用现有架构,也是个不少的挑战。
既然如此,没有
Node
适用的场景吗?
有。正如前文所说,Node
的意义是在于让前端掌握模板与模板所依赖数据,不妨从这两方面去进行考虑。如若重 SEO 的同时,页面交互相对复杂,这时候接入 Node
作为中间层,我认为就是最佳实践。
其次是后端架构不断演变,开始转向微服务化之后,前端感到接口碎片化开始带来不少麻烦后,就应该考虑接入 Node
整合接口了。
总的来说,什么时候接入 Node
, 有点像什么时候引入 Redux
或 Vuex
。当你感觉到麻烦后,只要你知道还有这个选项,自然而言地就会想到用它。
小结
综上所述,在以下场景中,我认为接入 Node
是最佳实践:
- 重视 SEO 且交互复杂。
- 后端微服务化,前端需要整合接口。
- 前端主导的项目,需要用到最新技术,如
SSR
、PWA
等。
如若只是性能问题,引入 Node
不一定会有改善,需要根据实际情况进行分析。至于后端的接口设计太丑陋、返回的数据结构不符合前端使用等问题,在应用规模不大的情况下,其实都是可以和后端同学进行沟通的,以此接入 Node
不一定是最佳的实践,需要好好思量。
但是,坚决反对只是因为现有架构比较熟悉而不愿改变,始终抱着错误的方案不去解决的做法,这绝对是舍本逐末。我始终认为,只要是对的事情,尽管过程再艰难,亦应该朝着对的方向前进。
以上是个人的一点浅见,感谢各位看官大人看到这里。知易行难,希望本文对你有所帮助~谢谢!