咱們團隊的後端服務中,一開始只有一個大服務,全部的東西都往裏面寫,能夠想象下,當這個服務變得不斷的龐大,將會變得多麼難以維護。後來逐漸把一些數據服務抽離成單獨的 API 服務,在原有的服務裏,就還剩一些模板渲染,數據聚合還有一些耦合的業務邏輯。目前來講拆的還不夠乾淨,咱們的目標實際上是但願這個舊的服務充當一個 API Gateway,或者說一個給前端用的中間層。單一職責原則,實際上是一個很重要的解耦方式,一個服務幹好一件事就行了。偶然間看到下面的文章,雖然只是一些很簡單的介紹,也讓我瞭解到不少東西。也分享給 你們看看。前端
閱讀原文node
客戶端通常都須要通過一些認證以及知足在數據傳輸時的安全要求,才能得到訪問微服務架構中的服務的權利。不一樣的服務在認證上都會或多或少存在一些差別,API Gateway 就像一個集線器,用它來抹平各類服務協議之間的差別,並知足對特定客戶端的特殊處理。他的存在,方便了客戶端對各種服務的享用。nginx
微服務適合用在團隊能夠獨立設計、開發、運行服務的架構體系中。它容許系統中的各個服務存在技術多樣性,團隊能夠在適合的場景使用合適的開發語言、數據庫和網絡協議。例如,一個團隊中使用 JSON 和 HTTP REST,而另外一個團隊則可能使用 gRPC 和 HTTP/2 或者像 RabbitMQ 這樣的消息代理。數據庫
有些場景中使用不一樣的數據序列化方式和協議可能收益巨大,可是須要使用咱們服務的客戶端可能會有不一樣的需求。因爲存在各類各樣的客戶端,須要咱們支持的數據格式也是多種多樣,好比一個客戶端可能但願拿到的數據是 XML 格式的,而另外一個客戶端則但願數據是 JSON。另外一個你可能須要面對的問題是,可能不一樣服務之間存在着一些公共的邏輯(好比權限認證之類),總不能在每一個服務裏都實現一遍吧?express
總結:咱們不想把一些支持多個客戶端等相關的公用邏輯重複實如今微服務中,咱們須要一個 API Gateway 來提供一箇中間層來處理服務協議之間的差別,並知足特定客戶端的需求。json
API 網關是微服務架構中的一種服務,它爲客戶端提供共享層和 API,以便與內部服務進行通訊。 API 網關能夠路由請求,轉換協議,聚合數據,並實現一些共享邏輯,如身份驗證和速率限制器等。後端
你能夠將 API Gateway 看作是一個享用各類微服務的入口。api
咱們的系統能夠有一個或多個 API Gateway,這具體取決於客戶端的需求。例如,咱們能夠爲桌面瀏覽器,移動應用程序和公共API提供單獨的網關。promise
因爲 API Gateway 爲客戶端應用程序(如瀏覽器)提供了支持,它能夠由負責前端應用程序的團隊來實現和管理。瀏覽器
這也意味着 API Gateway 的實現語言應由負責客戶端的團隊選擇。因爲 JavaScript 是開發瀏覽器應用程序的主要語言,即便你的微服務架構用不一樣的語言開發,Node.js 也能夠成爲實現 API Gateway 的絕佳選擇。
Netflix 成功地使用 Node.js API Gateway 及其 Java 後端來支持普遍的客戶端, 瞭解更多。
咱們以前討論過,能夠將通用共享邏輯放入 API Gateway,本節將介紹其常見用法。
咱們將 API Gateway 定義爲微服務的入口。 在你的 API Gateway 中,你能夠將請求從客戶端路由到指定的服務。 你甚至能夠在路由期間對服務程序的版本進行選擇或更改後端接口,而公開的接口能夠保持不變。你還能夠在你的 API Gateway 中集合多個微服務到一點。
API Gateway 能夠幫助你分解臃腫的應用程序。因爲業務的不斷迭代,從頭開始把整個應用重寫成一個微服務架構的系統彷佛不太可行。
在這種狀況下,咱們能夠將代理或 API Gateway 置於咱們的總體應用以前,並將新功能做爲微服務實現,只須要保證 API Gateway 能將新接口路由到新服務,同時保證舊接口依然可以訪問。慢慢的咱們要把這些舊的服務遷移成微服務以達到分解臃腫應用程序的目的。
經過小步迭代設計,咱們可以平滑的從龐大的總體過渡到微服務架構。
大多數微服務是須要經過認證纔可使用的。將相似身份驗證的共享邏輯放在 API Gateway 上可讓你的微服務更加專一。
在微服務架構中,您能夠經過網絡配置將服務放置於 DMZ(非軍事區域)中,並經過API Gateway 將其暴露給客戶端。該網關還能夠處理多個身份驗證方法,例如,能夠支持基於cookie和基於 token 的身份驗證。
在微服務架構中,客戶端可能會須要不一樣聚合程度的數據。 在這種狀況下,咱們可使用 API Gateway 來解決這些依賴關係並從多個服務收集數據。
這種問題發生在不一樣客戶端須要不一樣格式數據的需求中。
想象一下,在微服務中若是咱們使用了 JSON,可是在某個客戶端中只支持 XML 的 API,這個時候怎麼辦?咱們徹底能夠把 JSON 轉換 XML 這一過程放在 API Gateway 中,而不是在每一個微服務中實現。
微服務架構容許使用不一樣的協議以便於得到使用不一樣技術的優點。然而,大多數客戶端只支持一種協議。在這種狀況下,咱們須要轉換客戶端的服務協議。
API Gateway 也能夠成爲介於客戶端和微服務之間的一個協議轉換層。
下面的圖片中你能夠看到,客戶端只使用 HTTP REST 來和各類服務交換信息,而實際上咱們內部的各類微服務能夠基於不一樣的規範、協議來進行信息傳遞。
除了身份驗證以外,你還能夠在 API Gateway 中實現速率限制,緩存和各類可靠性相關的功能。
在實現 API Gateway 時,應當避免將非通用邏輯(如領域特定數據轉換)放入其中。
服務應始終對其數據域擁有徹底的全部權。 構建一個過於龐大的 API Gateway,從服務團隊爭奪控制權,這違反了微服務的理念。
這就是爲何你應該注意你的API網關中的數據聚合 —— 若是你明確它的職責,它能夠是很強大的,應當避免在 API Gateway 中處理業務邏輯,是誰的事情就交給誰幹,必定要明確其在整個架構中的角色。
若是你但願在 API Gateway 中執行一些簡單的操做,例如將請求路由到特定的服務,你可使用像nginx這樣的反向代理。 但在某些時候,你可能須要實現通常代理不支持的邏輯。 在這種狀況下,你能夠在 Node.js 中實現本身的 API Gateway。
在 Node.js 中,你可使用 http-proxy 完成一些簡單的代理請求的服務,固然也可使用具備更多功能的 express-gateway。
在第一個 API Gateway 示例中,咱們在其代理請求到真實的服務以前,先進行權限認證。
const express = require('express') const httpProxy = require('express-http-proxy') const app = express() const userServiceProxy = httpProxy('https://user-service') // Authentication app.use((req, res, next) => { // TODO: my authentication logic next() }) // Proxy request app.get('/users/:userId', (req, res, next) => { userServiceProxy(req, res, next) })
另外一種方式是由 API Gateway 向微服務發送請求,再將響應回饋給客戶端:
const express = require('express') const request = require('request-promise-native') const app = express() // Resolve: 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 Gateway 提供了一箇中間層來協調客戶端和微服務架構。它有助於幫助咱們完成單一職責原則,讓咱們的應用或者服務持續的關注一件事。你能夠將通用邏輯放入 API Gateway 中,可是也應該注意不要過分的使用 API Gateway。