使用 YARP 实现微服务 API 网关


基于微服务的大型系统可以由数十甚至数百个单独的服务组成。客户端应用程序需要拥有所有这些信息才能直接向相关微服务发出请求。

然而,这存在许多问题,例如安全问题、复杂性增加和耦合。

我们可以通过引入一个API 网关来解决这个问题,该网关充当反向代理来接受来自客户端应用程序的 API 调用并将其转发到适当的服务。

API网关还增强安全性并确保可扩展性和高可用性。

这里讨论如何使用YARP 反向代理为您的微服务系统实现API 网关:

  • API网关和反向代理的区别
  • 安装和配置YARP
  • 使用YARP创建API 网关
  • API网关的认证和限速

API网关和反向代理有什么区别?
反向代理和API网关是类似的概念,但它们有不同的用途。

反向代理充当客户端和服务器之间的中介。客户端只能通过反向代理调用后端服务器,反向代理将请求转发到适当的服务器。它隐藏了内部网络内各个服务器的实现细节。
反向代理通常用于:

  • 负载均衡
  • 缓存
  • 安全
  • SSL

API网关是一种特定类型的反向代理,旨在管理 API。它充当 API 消费者访问各种后端服务的单一入口点。
API 网关的主要特征是:

  • 请求路由和组合
  • 请求/响应转换
  • 认证与授权
  • 速率限制
  • 监控

另请注意,API 网关可以执行负载平衡和针对反向代理提到的其他功能。
现在我们来看看如何使用反向代理来实现API网关。

安装和配置 YARP
YARP (Yet Another Reverse Proxy)是微软开发的一个库,旨在满足需要构建反向代理的各个团队的需求。它是开源的并使用 .NET 构建,因此它与现有的生态系统很好地集成。

让我们安装Yarp.ReverseProxy NuGet包来开始:

Install-Package Yarp.ReverseProxy

接下来,我们将调用:

  • AddReverseProxy添加YARP所需的服务
  • LoadFromConfig从应用程序设置加载反向代理配置
  • MapReverseProxy介绍一下反向代理中间件

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddReverseProxy()
    .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));

var app = builder.Build();

app.MapReverseProxy();

app.Run();

我们需要告诉YARP反向代理如何将传入请求路由到各个微服务。

YARP使用 的概念Routes来表示代理的请求模式并Clusters表示转发这些请求的服务。

{
    "ReverseProxy": {
        "Routes": {
            ...
        },
        "Clusters": {
            ...
        }
    }
}

下面是一个示例YARP 配置,其模式{**catch-all}将所有传入请求路由到一个目标服务器。

{
  "ReverseProxy": {
    "Routes": {
      "ROUTE_NAME": {
        "ClusterId": "CLUSTER_NAME",
        "Match": {
          "Path": "{**catch-all}"
        }
      }
    },
    "Clusters": {
      "CLUSTER_NAME": {
        "Destinations": {
          "destination1": {
            "Address": "https://www.milanjovanovic.tech/"
          }
        }
      }
    }
  }
}

使用 YARP 实现 API 网关
我们可以使用YARP来构建API 网关,为我们想要将流量路由到的服务提供配置。
我在 GitHub 上使用 YARP 创建了一个示例 API 网关实现,因此您可以尝试一下。该系统有两个服务:Users.Api和Products.Api​​ ,它们是 .NET 7 应用程序。

如果请求与 /users-service/{**catch-all}(例如 /users-service/users)相匹配,则会被路由到 users-cluster。同样的逻辑也适用于产品集群。我们可以通过 "转换 "部分应用更高级的转换。

{
  "ReverseProxy": {
    "Routes": {
      "users-route": {
        "ClusterId": "users-cluster",
        "Match": {
          "Path": "/users-service/{**catch-all}"
        },
        "Transforms": [{ "PathPattern": "{**catch-all}" }]
      },
      "products-route": {
        "ClusterId": "products-cluster",
        "Match": {
          "Path": "/products-service/{**catch-all}"
        },
        "Transforms": [{ "PathPattern": "{**catch-all}" }]
      }
    },
    "Clusters": {
      "users-cluster": {
        "Destinations": {
          "destination1": {
            "Address": "https://localhost:5201/"
          }
        }
      },
      "products-cluster": {
        "Destinations": {
          "destination1": {
            "Address": "https://localhost:5101/"
          }
        }
      }
    }
  }
}

现在,我们用 YARP 构建了一个正常运行的 API 网关,将请求路由到两个单独的服务。

添加身份验证
API网关可以在系统入口点强制执行身份验证和授权,然后再让经过身份验证的请求继续进行。

并且YARP支持与现有的认证授权中间件集成。

您首先需要定义授权策略:

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("authenticated", policy =>
        policy.RequireAuthenticatedUser());
});

并调用UseAuthentication和UseAuthorization将相应的中间件添加到请求管道中。在调用之前添加它们很重要MapReverseProxy。

app.UseAuthentication();

app.UseAuthorization();

app.MapReverseProxy();

现在您所要做的就是将该AuthorizationPolicy部分添加到反向代理配置中:

"users-route": {
  "ClusterId": "users-cluster",
  "AuthorizationPolicy": "authenticated",
  "Match": {
    "Path": "/users-service/{**catch-all}"
  },
  "Transforms": [
    { "PathPattern": "{**catch-all}" }
  ]
}

YARP会将大多数凭据转发到代理服务,例如 cookie 或不记名令牌,因为在各个微服务中识别用户可能很重要。


添加速率限制
您还可以使用API 网关向系统引入速率限制。这是一种限制对 API 的请求数量的技术,以提高安全性并减少服务器的负载。

正如您已经猜到的,YARP支持.NET 7 中添加的本机速率限制机制。

您需要做的就是定义速率限制策略:

builder.Services.AddRateLimiter(rateLimiterOptions =>
{
    rateLimiterOptions.AddFixedWindowLimiter("fixed", options =>
    {
        options.Window = TimeSpan.FromSeconds(10);
        options.PermitLimit = 5;
    });
});

然后需要调用将UseRateLimiter速率限制器中间件添加到请求管道中。在致电之前执行此操作很重要MapReverseProxy。

app.UseRateLimiter();

app.MapReverseProxy();

然后,您可以使用RateLimiterPolicy反向代理配置中的部分对所需路由应用速率限制:

"products-route": {
  "ClusterId": "products-cluster",
  "RateLimiterPolicy": "fixed",
  "Match": {
    "Path": "/products-service/{**catch-all}"
  },
  "Transforms": [
    { "PathPattern": "{**catch-all}" }
  ]
}

总之
API网关是实现稳健的微服务系统的关键组件。
如果您想使用 .NET 构建API 网关,YARP是一个很好的选择。

如果您想了解更多信息,这里有一些有用的资源: