前后端同构在去哪儿项目中的实践

痛点

传统开发模式:模板文件放在后端工程目录下,通过pom文件实现前端资源关联。

1.前后端在view层工作重复,前后端严重依赖vm文件
2.前端依赖后端开发环境,mock数据停留在页面级别
3.传统的客户端ajax异步请求数据,页面有明显loading时间
4.前端无法有效推动后端工作

node如何解决痛点?
1.view层彻底交给前端,后端只需要专注于复杂业务逻辑,提供数据
2.node做中间层,摆脱对后端开发环境的依赖,更多可能
3.简单的数据聚合工作,node完全可以胜任
4.前后端工作都由前端同学完成,沟通成本低,响应速度更快
5.业务场景决定,活动页面专题页面居多,天然适合

为了解决上面这些痛点,联系实际的业务场景,我们用node搭建了自己的ssr项目event(前后同构)

实践

技术选型

去哪儿内部的一个node框架叫做qxf,是基于express自研的。优点很明显:
1.通过插件的形式,打通了公司的其他环节,比如qconfig,watcher等
2.内置了服务启动脚本,业务不用更多的关注发布流程
3.内部自己人维护,可及时响应

实际使用中也发现了一些问题,比如
1.没有明确的项目目录规范,各个团队各种写法都有。
2.多进程管理不够优雅,传统的fork进程写法容易侵入了业务代码中
3.不能有效区分多环境(local/beta/prod)
4.部分插件功能不够完善
5.在生产环境中如何确保系统的安全性,稳定性

社区内也有一些知名企业级方案,像阿里的egg,360的think等。

经过团队讨论,出于社区生态的考虑,最后还是选择了阿里开源的egg

部署

event立项之初,传统的项目发布方式对node并不友好,项目中常常需要写一个发布脚本,然后交给jekins执行。这带来了很多问题。比如一份脚本如何有效区分beta和prod环境?如何利用发布系统中的端口,部署路径等信息?尤其是写shell命令,大大增加了前端同学的学习成本。

但实际上不同项目除了部署路径,端口等少部分信息不同外,逻辑大部分是相似的。经过百放老师的努力和推动,最终发布系统优化了jenkins的发布方式,使其对node项目更友好。现在只需要在项目下设置一个简单的start.sh文件(在sh文件中设置npm安装,启动node服务,只有几行命令),然后在发布系统中选择node类型,然后填入端口,部署路径等信息即可。

遇到的问题

服务端如何引用前端组件,如何管理action

设备嗅探

有时候不同的设备,前端可能要渲染不同的UI。但ssr时服务端如何拿到设备信息呢?

服务端在响应接口请求时,是能拿到设备UA的,我们的做法就是解析UA, 得到设备信息Sniff,然后将这个Sniff注入全局store中,这样服务端在render时就能拿到设备信息了。其实还有一种解法:就是服务端先预设一个UI, 等客户端渲染时再真正填充。这两者我觉得可以结合起来。

经纬度相关

需要获取经纬度才能提供服务的场景怎么办?一般经纬度都是由客户端异步获取的,ssr时怎么拿到这个值?

不妨换个思路,利用ip获取经纬度或者经纬度在请求模板html文件时作为参数传入

如何有效管理接口

node需要访问java服务才能拿到数据,如何有效区分不同环境的接口地址?
我们把接口地址集中管理,放在一个全局文件下维护,借由egg提供的多环境机制可以很容易的做到环境隔离。

接口透传

有些接口服务event只做最简单的透传工作,如果按照egg的设计,每个服务都要提供一个service层,那会造成极大的冗余浪费,能否优化?
统一封装透传接口,暴露给前端页面使用,前端通过访问服务端暴露出来的接口直接请求后端java数据,event无需再写相应的service

实践心得

1.合理的利用缓存能够极大提高性能,比如缓存模板,缓存数据
2.中间件不是越多越好,数量越多,也就意味着处理链路越长,损耗越多
3.区分node环境和客户端环境。前后端同构的代码很可能会同时执行在服务端和客户端,但两者有些不同,部分变量服务端是没有的,比如window,dom等
4.客户端可能存在cookie含非法字符的情况,所以后端在解析cookie时需要使用try/catch包裹

日志监控

服务端的日志监控接入了去哪儿已有的kibanna + watcher服务
accesslog, 异常详情等信息都被统计到kibana上来可以实时预览
接口耗时,调用次数等信息被watcher打点记录。

event监控结构

event生态

难点

qconfig

很多时候我们需要频繁的修改某些程序参数,如果这些配置参数直接写在代码里,每次更新都要发布代码,显然不现实。如果我们能把这些配置参数配置在文件中集中管理,然后程序在代码中访问。以后如果需要修改参数,直接修改相关配置文件即可。

qconfig就是提供这种功能的一套服务。它具有多个特性,比如配置和代码相分离,集中管理所有的配置;热发布配置文件。失败回滚等等,在去哪儿内部广泛使用。

event作为一个后端服务,免不了要和qconfig打交道。但qconfig提供的基本都是java接口。因此node需要自己实现访问qconfig的功能。

dubbo

浏览器里js只需要关心http接口就可以,但是作为服务端语言,免不了要和其他RPC服务打交道。因此如何使用node访问其他RPC服务就是个问题。
部分后端服务是由dubbo提供的,因此node如何访问dubbo服务是event要解决的问题。

遗憾的是这一点event做的不够好,因为场景里dubbo服务的数量不多,为了减少学习成本,后端同学直接帮忙把dubbo服务转为http形式了。
这是event后面要解决的问题

-------------本文结束 感谢您的阅读-------------