在先后端联调时,有些麻烦出现的频率不低并且可能会较大程度影响开发效率,其中就包括先后端对接口数据格式设计的差别。二者一是基于领域模型,一是基于用户交互,所以设计出来的数据结构常常有差别,使得前端从接口取到数据后还须要多作一层“数据规格化”(我本身的称呼…)的工做。举两个例子:前端
命名习惯不一致,例若有这样的一个列表数组ranks:node
[nginx
{ id: 1, value: 'DUCHY' }, { id: 2, value: 'KINGDOM' }, { id: 3, value: 'EMPIRE' }
]
页面的渲染组件须要value这一属性名,但接口数据使用的是name,那么就须要作一个遍历,手动修改属性名。后端
相似的状况还有(null、’’)/([]、{})的转换等等,这都是为了数据格式所作的额外操做,与业务逻辑并无太大关联。api
为复用某些接口,须要作一些接口数据额外处理:数组
数据对象info:性能优化
{数据结构
countries: [ { name: 'Austria', cities: [ 'Vienna', 'Tirol' ] }, { name: 'Persia', cities: [ 'Isfahan', 'Shiraz' ] }, { name: 'United States', cities: [ 'San Francisco', 'Mountain View' ] } ]
}
如今有一个场景,我只想要countries数组的第一项(或者说,在特定场景下只有第一项是有意义的),那么我若是复用这一接口拿到的数据,每次就都要作一个let specifiedCountry = countries[0]的默认赋值,在更复杂的场景下这种赋值可能嵌套更深、重复次数更多。并发
显然,处理数据格式与处理交互时的数据变化应该分离,这样前端会有更多精力去处理交互的业务逻辑。负载均衡
要应对这一需求,当下的GraphQL是一个不错的方案,用它能够作到指定一个请求格式,而后获取所需的数据,同时它也支持一些逻辑判断和抽象,如directive、Fragment、Variable等等,如下取这三个做为例子,演示一下对于上述例子的解决方案:
对于(一)中的第一个例子:
考虑GraphQL的alias解决方案:GraphQL的别名alias设计目的是在同一个Type下能够返回多个对象而不发生命名冲突,不过咱们也能够用它作一下name -> value 的重命名:
ranks {
id value: name
}
*嵌套的别名是否可行未知,还须要作一下验证
对于(一)中的第二个例子:
使用variable和directive作一些逻辑处理:
query Country($isFirst: Boolean!) {
info(episode: $episode) { countries @include(if: $isFirst) { name cities } }
}
数据模型中,第一个元素包含isFirst: true便可(这里可能还要深究一下,isFirst如何设置才能真正解决原来的问题,或者说须要别的判断方式)
BFF的应用场景有不少,聚合后端接口,提供给第三方api都是它能够负责的工做。聚合后端接口在上文已经有了相似的操做,不过作的不是聚合几个接口而是对某个接口作了额外处理。
BFF层的设计通常来讲能够更好地知足产品快速迭代的需求,由于它将UI交互与部分服务都交给了一个team(能够是Frontend)负责,这样能够大大减小不一样team的沟通协调成本。
node.js也能够作一部分在BFF层的数据加密(放BFF层合适吗?)、请求转发(须要和nginx作一下对比)
也能够作一些性能优化的工做(依然要对比以往服务端的解决方案)
性能优化
高并发与负载均衡:常见的状况下,高并发的性能制约包括了大量的I/O操做时CPU利用率较低,而node.js在处理I/O密集型操做时有本身的优点。
在负载均衡方面,nginx有几套经常使用的请求分配方案,也有shared memory的解决方案,而且在保证会话一致性上有较好的表现。
node.js的clientRequest对象也会维护一个header queue,能够对请求的流程作必定的控制。