在先後端聯調時,有些麻煩出現的頻率不低並且可能會較大程度影響開發效率,其中就包括先後端對接口數據格式設計的差別。二者一是基於領域模型,一是基於用戶交互,所以設計出來的數據結構常常有差別,使得前端從接口取到數據後還須要多作一層「數據規格化」(我本身的稱呼…)的工做。舉兩個例子:前端
命名習慣不一致,例若有這樣的一個列表數組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,能夠對請求的流程作必定的控制。