使用 Node.js 搭建一個 API 網關(助力微服務)

外部客戶端訪問微服務架構中的服務時,服務端會對認證和傳輸有一些常見的要求。API 網關提供共享層來處理服務協議之間的差異,並滿足特定客戶端(如桌面瀏覽器、移動設備和老系統)的要求。

微服務和消費者

微服務是面向服務的架構,團隊可以獨立設計、開發和發佈應用程序。它允許在系統各個層面上的技術多樣性,團隊可以在給定的技術難題中使用最佳語言、數據庫、協議和傳輸層,從而受益。例如,一個團隊可以使用 HTTP REST 上的 JSON,而另一個團隊可以使用 HTTP/2 上的 gRPC 或 RabbitMQ 等消息代理。

在某些情況下使用不同的數據序列化和協議可能是強大的,但要使用我們的產品的客戶可能有不同的需求。該問題也可能發生在具有同質技術棧的系統中,因爲客戶可以從桌面瀏覽器通過移動設備和遊戲機到遺留系統。一個客戶可能期望 XML 格式,而另一個客戶可能希望 JSON 。在許多情況下,你需要同時支持它們。

當客戶想要使用你的微服務時,你可以面對的另一個挑戰來自於通用的共享邏輯(如身份驗證),因爲你不想在所有服務中重新實現相同的事情。

總結:我們不想在我們的微服務架構中實現我們的內部服務,以支持多個客戶端並可以重複使用相同的邏輯。這就是 API 網關出現的原因,其作爲共享層來處理服務協議之間的差異並滿足特定客戶端的要求。

什麼是 API 網關?

API 網關是微服務架構中的一種服務,它爲客戶端提供共享層和 API,以便與內部服務進行通信。API 網關可以進行路由請求、轉換協議、聚合數據以及實現共享邏輯,如認證和速率限制器。

你可以將 API 網關視爲我們的微服務世界的入口點。

我們的系統可以有一個或多個 API 網關,具體取決於客戶的需求。例如,我們可以爲桌面瀏覽器、移動應用程序和公共 API 提供單獨的網關。

API 網關作爲微服務的切入點

Node.js 用於前端團隊的 API 網關

由於 API 網關爲客戶端應用程序(如瀏覽器)提供了功能,它可以由負責開發前端應用程序的團隊實施和管理。

這也意味着用哪種語言實現 API Gateway 應由負責特定客戶的團隊選擇。由於 JavaScript 是開發瀏覽器應用程序的主要語言,即使你的微服務架構以不同的語言開發,Node.js 也可以成爲實現 API 網關的絕佳選擇。

Netflix 成功地使用 Node.js API 網關及其 Java 後端來支持廣泛的客戶端 ,如果想要了解更多關於它們的方法,可以看看這篇文章 The "Paved Road" PaaS for Microservices at Netflix

API 網關功能

我們之前討論過,可以將通用共享邏輯放入你的 API 網關,本節將介紹最常見的網關職責。

路由和版本控制

我們將 API網關定義爲你的微服務的入口點。在網關服務中,你可以指定從客戶端路由到特定服務的路由請求。甚至可以通過路由處理版本或更改後端接口,而公開的接口可以保持不變。你還可以在你的API網關中定義與多個服務配合的新端點。

API 網關作爲微服務入口點

網關設計的進化

API網關方法可以幫助你分解整體應用程序。在大多數情況下,作爲微服務端,重構系統並不是一個好主意,而且也是不可能的,因爲我們需要在過渡期間爲業務提供功能。

在這種情況下,我們可以將代理或 API 網關置於我們的整體應用程序之前,將新功能作爲微服務實現,並將新端點路由到新服務,同時通過原有的路由服務舊端點。這樣以後,我們也可以通過將原有功能轉變爲新服務來分解整體。

通過漸進式設計,我們可以從整體架構平穩過渡到微服務。

認證方式

大多數微服務基礎架構都需要處理身份驗證。將身份驗證之類的共享邏輯放入API網關可以幫助你縮小服務的體積專注管理域

在微服務架構中,你可以通過網絡配置將服務保留在DMZ(保護區)中,並通過API網關將其公開給客戶端。該網關還可以處理多種身份驗證方法,例如,你可以同時支持基於cookie和token的身份驗證。

具有認證功能的 API 網關

數據彙總

在微服務體系結構中,可能會發生客戶端需要不同聚合級別的數據的情況,例如對各種微服務中產生的數據實體進行非規範化。在這種情況下,我們可以使用我們的API網關來解決這些依賴關係並從多個服務中收集數據。

在下圖中,你可以看到API 網關 如何合併用戶和信用信息,並作爲一條數據返回給客戶端。請注意,它們由不同的微服務擁有和管理。

序列化格式轉換

我們可能需要支持具有不同數據序列化格式要求的客戶端。想象一下這種情況:我們的微服務使用JSON,但是我們的一位客戶只能使用XML API。在這種情況下,我們可以在API網關中將JSON轉換爲XML,而不是在所有微服務中去實現。

協議轉換

微服務架構允許多語言協議傳輸從而獲得不同技術的好處。但是,大多數客戶端僅支持一種協議。在這種情況下,我們需要爲客戶端轉換服務協議。

API 網關還可以處理客戶端和微服務器之間的協議轉換。

在下一張圖片中,你可以看到客戶端希望通過 HTTP REST 進行的所有通信,而內部的微服務使用 gRPC 和 GraphQL 。

限速和緩存

在前面的例子中,你可以看到我們可以把通用的共享邏輯(如身份驗證)放在 API 網關中。除了身份驗證之外,你還可以在 API 網關中實現速率限制,緩存以及各種可靠性功能。

超負荷的 API 網關

實現API網關時,應避免將非通用邏輯(例如特定領域的數據轉換)放入網關。服務應始終對其數據域擁有完全所有權。構建一個超負荷的API網關,讓微服務團隊來控制,這違背了微服務的理念。

這就是爲什麼你應該謹慎使用API網關中的數據聚合的原因,使用起來可能功能強大,但也應避免的特定於域的數據轉換或規則處理邏輯。

始終爲你的 API 網關定義明確的責任,並且只包括其中的通用共享邏輯。

Node.js API 網關

當你希望在 API 網關中執行簡單的操作,比如將請求路由到特定服務,你可以使用像 nginx 這樣的反向代理。但在某些時候,你可能需要實現一般代理不支持的邏輯。在這種情況下,你可以在 Node.js 中實現自己的 API 網關。

在 Node.js 中,你可以使用 http-proxy 軟件包簡單地代理對特定服務的請求,也可以使用更多豐富功能的 express-gateway 來創建 API 網關。

在我們的第一個 API 網關示例中,我們在將代碼委託給 user 服務之前驗證請求。

   const express = require('express')
    const httpProxy = require('express-http-proxy')
    const app = express()

    const userServiceProxy = httpProxy('https://user-service')

    // 身份認證
    app.use((req, res, next) => {
      // TODO: 身份認證邏輯
      next()
    })

    // 代理請求
    app.get('/users/:userId', (req, res, next) => {
      userServiceProxy(req, res, next)
    })

另一種示例可能是在你的 API 網關中發出新的請求,並將響應返回給客戶端:

   const express = require('express')
    const request = require('request-promise-native')
    const app = express()

    // 解決: GET /users/me
    app.get('/users/me', async (req, res) => {
      const userId = req.session.userId
      const uri = `https://user-service/users/${userId}`
      const user = await request(uri)
      res.json(user)
    })

Node.js API 網關總結

API 網關提供了一個共享層,以通過微服務架構來滿足客戶需求。它有助於保持你的服務小而專注。你可以將不同的通用邏輯放入你的 API 網關,但是你應該避免API網關的過度使用,因爲很多邏輯可以從服務團隊中獲得控制。

譯文:Building an API Gateway using Node.js

地址:https://blog.risingstack.com/building-an-api-gateway-using-nodejs/

支持

如果你覺得這篇內容對你挺有啓發,我想邀請你幫我三個小忙:

  1. 點個「在看」,讓更多的人也能看到這篇內容(喜歡不點在看,都是耍流氓 -_-)

  2. 關注我的官網 https://muyiy.cn,讓我們成爲長期關係

  3. 關注公衆號「高級前端進階」,公衆號後臺回覆「面試題」 送你高級前端面試題,回覆「加羣」加入面試互助交流羣

》》面試官都在用的題庫,快來看看《《

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章