掘金 后端 ( ) • 2024-04-19 16:14

本文全面讲解了API网关在现代软件架构中的关键角色,还比较了Node.js环境下两个主要的代理库——express-http-proxyhttp-proxy,并通过一个实际示例展示了如何利用Express框架和http-proxy库构建一个简易的API网关。这不仅展示了API网关简化服务交互、提升系统安全性和可维护性的能力,还提供了选择代理库和设计API网关的实用指南。

架构勤杂工——API网关

API网关在现代软件架构中扮演着至关重要的角色,特别是在微服务架构、老旧系统整合、多云环境、第三方服务集成、移动应用、物联网(IoT)应用以及服务版本管理和蓝绿部署等方面。下面,我们将详细探讨API网关在这些场景中的作用。

微服务架构

在微服务架构中,系统被划分为一系列小的、自治的服务,每个服务实现特定的业务功能。API网关在这种架构中起到了流量协调员的作用,它负责将外部请求路由到正确的服务实例,同时还提供服务发现、负载均衡、故障转移等功能。此外,API网关作为安全屏障,通过统一的身份验证和授权机制保护微服务不受恶意访问。

老旧系统整合和治理

对于那些包含遗留系统的企业,API网关提供了一个平滑的过渡层,使得这些老旧系统能够更容易地与现代应用集成。通过封装遗留接口,API网关使得它们对外展现出现代化的、一致的API接口。这不仅有助于提高开发效率,还能为遗留系统提供现代化的安全防护。

多云和混合云环境

在采用多云或混合云策略的企业中,API网关扮演着关键的桥梁角色,确保不同云环境和本地数据中心之间服务的无缝连接和数据的安全传输。它简化了跨云API调用的管理,使得企业能够更加灵活地利用多云资源。

第三方服务集成

API网关极大地简化了第三方服务的集成过程,使企业能够通过统一的接口访问外部API,如社交媒体、支付网关等。这不仅加快了开发速度,还确保了集成的安全性和监控。

移动应用后端服务

对于移动应用,API网关优化了与后端服务的通信,通过技术如缓存、数据压缩等提高响应速度。此外,它还管理着认证和授权过程,保障移动应用的数据交互安全。

IoT应用

在IoT领域,API网关管理着成千上万的设备连接和数据传输。它支持设备认证、数据加密和消息路由,确保大规模IoT系统的高效和安全运行。

服务版本管理和蓝绿部署

API网关通过灵活的路由控制支持服务的平滑升级和版本管理。企业可以利用API网关实现蓝绿部署和金丝雀发布,无缝地将用户流量迁移到新版本,从而降低更新带来的风险。

总之,API网关作为现代软件架构中的关键组件,通过提供统一的入口点和一系列高级功能,不仅简化了服务之间的交互,还提高了系统的安全性、可扩展性和可维护性。

NodeJS代理库

express-http-proxy

express-http-proxy是一个为Express框架设计的中间件,它允许Express应用将接收到的HTTP请求代理转发到另一个服务器。这个库主要用于在Express应用中实现反向代理功能,它简化了代理的配置和处理流程,使得开发者能够轻松地在Express应用中集成复杂的代理逻辑。

主要特性

  • 易于集成:作为Express的中间件,express-http-proxy可以非常容易地集成到任何基于Express的应用中。
  • 灵活的URL重写:支持请求URL的重写,允许开发者修改代理请求的路径。
  • 响应处理:提供了修改代理响应的能力,开发者可以在将响应发送给客户端之前对其进行处理。
  • 自定义代理规则:允许开发者基于请求的特定属性(如头信息、查询参数等)定义复杂的代理规则。

http-proxy

http-proxy是一个功能强大的HTTP代理库,它支持代理HTTP和WebSocket请求。与express-http-proxy不同,http-proxy不依赖于Express或任何其他特定的Web框架,这使得它可以在多种Node.js应用场景中使用,包括但不限于Express应用。

主要特性

  • 框架无关:可以在任何Node.js应用中使用,不限于Express。
  • 高性能:专为处理高并发请求而设计,适合构建高性能的代理服务器。
  • WebSocket支持:原生支持WebSocket代理,适合需要代理实时通讯请求的应用。
  • 高度可定制:提供了丰富的配置选项和API,允许开发者实现复杂的代理逻辑,包括负载均衡、SSL终止等。

对比express-http-proxyhttp-proxy

在选择express-http-proxyhttp-proxy时,主要的考虑因素包括应用的具体需求、性能要求、以及开发者对框架依赖的偏好。

  • 框架依赖:如果你正在开发一个Express应用并且需要简单的代理功能,express-http-proxy可能是更合适的选择,因为它可以无缝集成到Express应用中。而http-proxy更适合那些需要在不同类型的Node.js应用中实现复杂代理逻辑的场景,或者需要高性能处理大量并发请求的应用。
  • WebSocket支持:如果你的应用需要代理WebSocket连接,http-proxy将是更好的选择,因为它原生支持WebSocket代理。
  • 性能和可扩展性:对于高负载环境和需要高度定制代理逻辑的应用,http-proxy提供了更高的性能和更好的可扩展性。

fastify还有个插件@fastify/http-proxy,这个在我的fastify系列博客中重点应用一下

Express实现简单API网关

在前面的讨论中,我们已经涵盖了Node.js Web服务器生态系统的广泛领域,包括各种服务端框架、服务端渲染(SSR)技术、全栈框架以及API网关的重要性和实现方法。现在,我们将通过一个具体的示例来展示如何使用Express框架实现一个简单的API网关。这个API网关将使用http-proxy库来代理请求,因为它提供了对WebSocket的支持和更高的性能及可扩展性。

需求分析

有个P需求,上面罗列的这些都不是一个人能搞定的。所以我们先拍出来几个需求,后面如果有机会就深入的搞一下:

1. 代理后端服务

代理后端服务的主要目的是将来自客户端的请求转发到实际的后端服务,并将后端服务的响应返回给客户端。这样做有几个好处:

  • 抽象化服务地址:客户端不需要知道后端服务的具体地址,只需要与API网关交互。这有助于服务的迁移和扩展,因为改变服务的位置不会影响到客户端。
  • 负载均衡和故障转移:通过在多个后端服务之间分配请求,可以提高系统的可用性和容错能力。
  • 安全性:API网关可以作为安全层,实施认证、授权和数据加密,保护后端服务免受未授权访问。

实现这一需求时,我们需要考虑如何配置路由规则,以及如何处理不同类型的请求(如GET、POST等)。此外,还需要考虑如何处理服务发现和动态路由,以支持微服务架构下服务的动态变化。

2. 处理跨域请求

跨源资源共享(CORS)是现代Web应用常见的需求,特别是当前端应用和后端服务部署在不同的域名下时。处理跨域请求的目的是允许或限制来自不同源的前端应用访问API。

为了实现这一需求,API网关需要能够在响应中加入正确的CORS头部,如Access-Control-Allow-Origin。这可能需要配置一些规则,指定哪些源可以访问哪些资源,以及它们可以使用哪些HTTP方法和头部。

3. 增强的错误处理

在代理请求或处理跨域时,可能会遇到各种错误,如网络错误、服务不可用、请求超时等。增强的错误处理的目的是提供更详细的错误信息,帮助开发者和最终用户理解和解决问题。

实现这一需求时,我们需要考虑如何捕获和记录错误,以及如何向客户端返回有用的错误信息。这可能包括定义错误格式、记录错误日志和集成监控工具。

代理库选择

注意,http-proxy最后一次提交已经是4年前了

Commits on May 18, 2020(2020年5月18日)

在选择代理库时,我们考虑了以下几个关键因素:

  • 性能:在处理高并发请求时,代理库的性能至关重要。http-proxy是一个高性能的HTTP代理库,专为处理大量并发请求而设计,这使它成为构建高性能API网关的理想选择。
  • 可扩展性:随着系统的扩展,API网关可能需要支持更多的后端服务和复杂的路由规则。http-proxy提供了丰富的API和配置选项,使得扩展和自定义代理逻辑变得简单。
  • WebSocket支持:对于需要实时通信功能的应用,WebSocket支持是必不可少的。http-proxy原生支持WebSocket代理,这意味着我们的API网关可以无缝地支持实时通信需求。
  • 社区支持和稳定性http-proxy拥有活跃的社区支持和良好的文档,这有助于解决开发过程中的问题,并确保库本身的稳定性和安全性。

基于上述考虑,http-proxy成为了我们选择的代理库。

设计思路

为了实现一个高效、可靠的API网关,我们采取以下设计思路:

  1. 初始化Express应用
    • 创建一个Express应用实例,作为API网关的基础。
    • 配置全局中间件,如日志记录器、请求解析器和CORS处理器,以支持基本的Web服务功能。
  2. 配置代理规则
    • 根据业务需求和系统架构,定义一组路由规则。这些规则将根据请求的路径或其他属性(如请求头或查询参数)将请求路由到不同的后端服务。
    • 使用http-proxy库创建代理服务器实例,并为每个路由规则配置相应的代理目标。这可能包括不同的后端服务地址、路径重写规则和特定的HTTP头处理逻辑。
  3. 错误处理
    • 在代理过程中,可能会遇到各种错误,如网络错误、目标服务不可达或超时等。为了提高系统的健壮性,我们需要实现一个全局错误处理机制。
    • 错误处理逻辑应该能够捕获和记录错误详情,同时向客户端返回友好的错误消息。这不仅有助于问题的调试和解决,也能提升最终用户的体验。
  4. 安全和认证(可选,根据需求):
    • 在某些场景下,API网关还需要处理安全相关的任务,如请求认证、API密钥验证和SSL终端。
    • 我们可以在Express应用中集成相应的中间件或自定义逻辑,以实现这些安全功能。

关键代码

以下是使用Express和http-proxy实现上述设计思路的关键代码:

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

// 创建一个代理服务器
const proxy = httpProxy.createProxyServer({});
const app = express();

// 代理规则示例
app.use('/service1', (req, res) => {
  proxy.web(req, res, { target: 'http://localhost:3001' });
});

app.use('/service2', (req, res) => {
  proxy.web(req, res, { target: 'http://localhost:3002' });
});

// 错误处理
proxy.on('error', (err, req, res) => {
  console.error(err);
  res.status(500).send('Proxy error');
});

// 启动服务器
const port = 3000;
app.listen(port, () => {
  console.log(`API Gateway running on http://localhost:${port}`);
});

保存到api.js

node api.js启动

访问http://localhost:3000/service1

API Gateway running on http://localhost:3000
Error: connect ECONNREFUSED 127.0.0.1:3001
    at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1495:16) {
  errno: -111,
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: '127.0.0.1',
  port: 3001
}
# 出现这个错误就代表我们流量转发成功了