- 原文地址:Building an API Gateway using Node.js
- 原文做者:Péter Márton
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:MuYunyun
- 校對者:jasonxia23、CACppuccino
外部客戶端訪問微服務架構中的服務時,服務端會對認證和傳輸有一些常見的要求。API 網關提供共享層來處理服務協議之間的差別,並知足特定客戶端(如桌面瀏覽器、移動設備和老系統)的要求。前端
微服務是面向服務的架構,團隊能夠獨立設計、開發和發佈應用程序。它容許在系統各個層面上的技術多樣性,團隊能夠在給定的技術難題中使用最佳語言、數據庫、協議和傳輸層,從而受益。例如,一個團隊可使用 HTTP REST 上的 JSON,而另外一個團隊可使用 HTTP/2 上的 gRPC 或 RabbitMQ 等消息代理。node
在某些狀況下使用不一樣的數據序列化和協議多是強大的,但要使用咱們的產品的客戶可能有不一樣的需求。該問題也可能發生在具備同質技術棧的系統中,由於客戶能夠從桌面瀏覽器經過移動設備和遊戲機到遺留系統。一個客戶可能指望 XML 格式,而另外一個客戶可能但願 JSON 。在許多狀況下,您須要同時支持它們。react
當客戶想要使用您的微服務時,您能夠面對的另外一個挑戰來自於通用的共享邏輯(如身份驗證),由於您不想在全部服務中從新實現相同的事情。android
總結:咱們不想在咱們的微服務架構中實現咱們的內部服務,以支持多個客戶端並能夠重複使用相同的邏輯。這就是 API 網關出現的緣由,其做爲共享層來處理服務協議之間的差別並知足特定客戶端的要求。ios
API 網關是微服務架構中的一種服務,它爲客戶端提供共享層和 API,以便與內部服務進行通訊。API 網關能夠進行路由請求、轉換協議、聚合數據以及實現共享邏輯,如認證和速率限制器。nginx
您能夠將 API 網關視爲咱們的微服務世界的入口點。git
咱們的系統能夠有一個或多個 API 網關,具體取決於客戶的需求。例如,咱們能夠爲桌面瀏覽器、移動應用程序和公共 API 提供單獨的網關。github
API 網關做爲微服務的切入點數據庫
因爲 API 網關爲客戶端應用程序(如瀏覽器)提供了功能,它能夠由負責開發前端應用程序的團隊實施和管理。express
這也意味着用哪一種語言實現 API Gateway 應由負責特定客戶的團隊選擇。因爲 JavaScript 是開發瀏覽器應用程序的主要語言,即便您的微服務架構以不一樣的語言開發,Node.js 也能夠成爲實現 API 網關的絕佳選擇。
Netflix 成功地使用 Node.js API 網關及其 Java 後端來支持普遍的客戶端 - 瞭解更多關於它們的方法閱讀 The "Paved Road" PaaS for Microservices at Netflix 這篇文章
Netflix 處理不一樣客戶端的方法, 資源
咱們以前討論過,能夠將通用共享邏輯放入您的 API 網關,本節將介紹最多見的網關職責。
咱們將 API 網關定義爲您的微服務的入口點。在您的網關服務中,您能夠指定從客戶端路由到特定服務的路由請求。您甚至能夠經過路由處理版本或更改後端接口,而公開的接口能夠保持不變。您還能夠在您的 API 網關中定義與多個服務配合的新端點。
API 網關做爲微服務入口點
API 網關方法也能夠幫助您分解您的總體應用程序。在大多數狀況下,在微服務端重構一個系統不是一個好主意也是不可能的,由於咱們須要在重構期間爲業務發送新的以及原有的功能。
在這種狀況下,咱們能夠將代理或 API 網關置於咱們的總體應用程序以前,將新功能做爲微服務實現,並將新端點路由到新服務,同時經過原有的路由服務舊端點。這樣之後,咱們也能夠經過將原有功能轉變爲新服務來分解總體。
隨着網關設計的升級,咱們能夠實現總體架構到微型服務的平滑過渡
API 網關設計的升級
大多數微服務基礎設施須要進行身份驗證。將共享邏輯(如身份驗證)添加到 API 網關能夠幫助您保持您的服務的體積變小以及能夠集中管理域。
在微服務架構中,您能夠經過網絡配置將您的服務保護在 DMZ (保護區)中,並經過 API 網關向客戶公開。該網關還能夠處理多個身份驗證方法。例如,您能夠同時支持基於 cookie 和 token 的身份驗證。
具備認證功能的 API 網關
在微服務架構中,可能客戶端所須要的數據的聚合級別不一樣,好比對在各類微服務中產生的非規範化數據實體。在這種狀況下,咱們可使用咱們的 API 網關來解決這些依賴關係並從多個服務收集數據。
在下圖中,您能夠看到 API 網關如何將用戶和信用信息做爲一個數據返回給客戶端。請注意,這些數據由不一樣的微服務所擁有和管理。
咱們須要支持客戶端不一樣的數據序列化格式這樣子的需求可能會發生。
想象一下咱們的微服務使用 JSON 的狀況,但咱們的客戶只能使用 XML APIs。在這種狀況下,咱們能夠在 API 網關中把 JSON 轉換爲 XML,而不是在全部的微服務器中分別進行實現。
微服務架構容許多通道協議傳輸從而獲取多種技術的優點。然而,大多數客戶端只支持一個協議。在這種狀況下,咱們須要轉換客戶端的服務協議。
API 網關還能夠處理客戶端和微服務器之間的協議轉換。
在下一張圖片中,您能夠看到客戶端但願經過 HTTP REST 進行的全部通訊,而內部的微服務使用 gRPC 和 GraphQL 。
在前面的例子中,您能夠看到咱們能夠把通用的共享邏輯(如身份驗證)放在 API 網關中。除了身份驗證以外,您還能夠在 API 網關中實現速率限制,緩存以及各類可靠性功能。
在實現您的 API 網關時,您應避免將非通用邏輯(如特定數據轉換)放入您的網關。
服務應該始終擁有他們的數據域的所有全部權。構建一個超負荷的 API 網關,讓微服務團隊來控制,這違背了微服務的理念。
這就是爲何你應該關注你的 API 網關中的數據聚合 - 你應該避免它有大量邏輯甚至能夠包含特定的數據轉換或規則處理邏輯。
始終爲您的 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)
})複製代碼
API 網關提供了一個共享層,以經過微服務架構來知足客戶需求。它有助於保持您的服務小而專一。您能夠將不一樣的通用邏輯放入您的 API 網關,可是您應該避免 API 網關的過分使用,由於不少邏輯能夠從服務團隊中得到控制。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、React、前端、後端、產品、設計 等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。