使用 Node.js 构建 API 网关
Posted 前端先锋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用 Node.js 构建 API 网关相关的知识,希望对你有一定的参考价值。
微服务框架中的服务提供了一些公用的认证和传输(业务)请求接口,用于给外部客户端调用。API Gateway提供了一个 shared layer(共享层),可用来处理服务协议,并满足特殊的客户端如桌面浏览器、手机设备或比较旧的系统的需要。
微服务 和 消费者
微服务是一个面向服务的框架,不同团队可以基于微服务独立地设计,开发并且推广他们的应用。微服务允许不同系统上的技术多样性,因此团队在面对技术上的挑战时可以使用最佳的语言,数据库,协议和传输层。例如,某个团队可以使用基于HTTP REST的JSON,而另一个团队可以使用基于HTTP/2的gRPC或是像RabbitMQ一样的消息代理。
某些情况下,使用不同的数据序列化方式和协议可以很强大,但是消费我们产品的客户端也许会有不同的需求。这个问题也会出现在同种技术栈的不同系统上,因为消费者可能是移动设备上的桌面浏览器,也可能是比较旧的系统的游戏控制台。某个客户端希望获取XML格式,而另外一个希望是JSON。在很多情况下,你需要两种都支持。
当客户端想要使用你的微服务时,另外一个挑战来自于像认证这种通用的共享逻辑,你肯定不想在你的所有的微服务里都重新实现一遍相同的东西。
总结:我们不想为了支持不同的客户端而在我们的微服务架构里重复实现相同的逻辑。这就是API Gateway出现的原因,API Gateway提供了一个共享层,用来处理不同服务协议的差异,并且实现特定客户端需求的。
什么是一个API Gateway?
API Gateway是微服务架构里的一种服务,它为那些需要和内部服务通信的客户端提供了共享层和接口。API Gateway可以路由请求,转换协议,整合数据和实现像认证和限速这样的共享逻辑。
你可以把 API Gateway看做是通往我们微服务世界的入口。
根据客户端的需求,我们的系统可以有一个或者多个API Gateway。例如,桌面浏览器,手机应用和公共API(s)都可以有一个单独的gateway。
API Gateway 作为微服务的入口
前端团队的Node.js API Gateway
由于API Gateway为像浏览器这种客户端应用提供功能,所以它可以由负责前端应用的团队来实现和管理。
这也意味着,实现API Gateway的语言,该由负责某个特定客户端的团队来选择。因为javascript是开发浏览器应用的基本语言,Node.js是实现一个API Gateway的极佳选择,即使你的微服务架构是用另外一种语言开发的。
Netflix成功地在他们的Java后台上使用Node.js API Gateway来支持不同的客户端 。
Netflix's 处理不同客户端的方式, source
API Gateway的各种功能
前文我们讨论过你可以把一些通用的共享逻辑放在API Gateway,这节将介绍gateway的通用功能。
路由和版本控制
我们把API Gateway定义为微服务的入口。在你的gateway服务里,你可以将一个客户端的请求路由至不同的服务。你甚至可以在路由时进行版本控制或者在暴露的公共接口不变的情况下改变后台接口。你也可以定义新的端点来配合不同的服务。
API Gateway 作为微服务的入口
演化式设计
API Gateway的方式也可以帮助你分解庞大的应用。在大部分情况下,从零开始重写你的系统为微服务不是一个好主意,而且在这个过渡期间,我们因为商业化原因,还需要发布新的特性,这也是不可能实现。
在这种情况下,我们可以为我们庞大的应用设置一个代理或者一个API Gateway,然后以微服务实现新的功能并路由新的端点到新的服务上,同时我们可以用原来的庞大的应用为旧的端点提供服务。后续我们可以通过新现存的功能移到新的服务的方式来分解原来庞大的应用。
通过这样演化式的设计,我们可以从原来庞大的应用平滑地过渡到微服务。
E用API Gateway的演化式设计
认证
大部分微服务需要处理认证。把像认证这种共享逻辑放在API Gateway可以让你的服务保持小巧并且域功能集中。
在微服务架构里,你可以通过网络配置保护你的服务在DMZ(控制区)里,同时把它们通过API Gateway暴露给客户端。这个gateway也可以处理多个认证方式。例如,你可以同时支持基于cookie或token的认证。
带认证的API Gateway
数据整合
在一个微服务架构里,客户端需要的数据可能存在于不同的整合层,像非常规数据实体。这种情况,我们可以用API Gateway来解决这种依赖,并从不同的服务收集数据。
如下图所示,API Gateway把user和credit信息进行合并,作为一块完整的数据返回给客户端。注意,这些数据是由不同的微服务拥有和管理的。
序列化格式转换
有可能我们需要支持有不同数据序列化格式需求的客户端。
有这样一个场景,我们的微服务使用JSON,但是某个用户只能用XML的接口。这种情况,我们可以把JSON到XML的转换放在API Gateway里,而不是在我们所有的微服务里都实现一遍。
协议转换
微服务架构通过允许多语言协议传输来获取不同技术的好处。但是大部分客户端仅支持一种协议。这种情况,我们需要为客户端转换服务协议。
API Gateway也可以在客户端和微服务之间处理协议转换。
如下图展示了,在我们内部微服务使用gRPC和GrapQL的情况下,客户端如何通过HTTP REST获取到所有的通信。
限速和缓存
前面的例子,你可以看见我们把像认证这种通用的共享逻辑放在API Gateway里。除了认证,你也可以在API Gateway里实现限速,缓存和各种可靠特性。
过度野心的API gateway
在实现你的API Gateway时,应当避免把非通用的逻辑 - 类似于域特定数据传输 - 放在你的gateway。
服务应该对于它们的数据域有绝对的控制权。创建一个管太多的API Gateway剥夺了服务团队的控制,这是违背微系统的哲学的。
这就是为什么你在你的API Gateway里小心处理数据整合 - 它可以很有用但是同时也可能导致域特定数据传输或者管理进程逻辑,这些是你应当避免的。
你应当为你的API Gateway定义清晰的职责并且仅包含通用的共享逻辑。
Node.js API Gateways
当你想在你的API Gateway里做一些简单的事情,像是路由请求至特定的服务,你可以使用类似于nginx这样的的反向代理。但是有时,你可能需要实现通用代理不支持的逻辑。这种情况,你可以用Node.js实现你自己的API Gateway。
使用Node.js,你可以仅用http-proxy包来把请求代理至某个特定的服务,或者可以使用特性更丰富的express-gateway来创建API gateway。
我们第一个API Gateway例子里,我们在代理请求至user服务前先认证了这个请求。
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)
})
Node.js API Gateways 总结
API Gateway使用微服务架构为客户端的需求提供了一个共享层。它帮助你保持服务的小巧和域集中。你可以把不同的通用逻辑放在你的API Gateway,但是你应当避免过度实现你的API Gateway,这将剥夺服务团队的控制。
往期精选文章 |
---|
小手一抖,资料全有。长按二维码关注京程一灯,阅读更多技术文章和业界动态。
以上是关于使用 Node.js 构建 API 网关的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Node.js 中使用带有 API 网关的 AWS Lambda 发送二进制响应? [复制]