- 原文地址: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、前端、后端、产品、设计 等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。