天天看点

使用 YARP 和 .Net 在 C# 中构建 API 网关

作者:opendotnet
使用 YARP 和 .Net 在 C# 中构建 API 网关

第一章 入门

当我们在平台中使用许多应用程序时,我们有许多配置,这些应用程序可能需要相互通信。在社区中,我们有一些模式可以解决这种情况,其中之一就是 API Gateway 模式。此解决方案位于客户端和应用程序之间,它负责路由请求的应用程序的请求、对请求进行身份验证和授权以及许多其他功能。

现在我们有很多API网关解决方案,比如Kong、KrakenD、Tyk和Apache APISIX,这些解决方案可以是开源的,也可以是授权的,每个都有自己的特点。在本文中,我们选择 YARP 是出于某些原因,这些原因是熟悉开发的代码语言,并且它是由 Microsoft 维护的开源库。

我们打算像一系列文章一样维护这一点,这些文章描述了使用 .Net 和 YARP 实现 api 网关的过程,并具有一些重要功能,如防火墙、速率限制、功能标志、身份验证等。

要开始这个项目,我们需要安装 dotnet 8 和 docker。

要开始我们的开发,我们要做的第一步是创建一个简单的应用程序来测试我们的路由和我们功能的适用性。

dotnet new web -o RoutingTestAPI
           

现在,在生成的程序文件中,我们将添加一些环境变量,以帮助我们可视化测试时的一些情况:

var defaultPath = Environment.GetEnvironmentVariable("ROOT_PATH"); 
var destination = Environment.GetEnvironmentVariable("DESTINATION"); 
var app = Environment.GetEnvironmentVariable("APP_NAME");
           

为了完成我们的代码,我们将添加一个端点来返回我们在路由请求时可以看到的内容:

app.MapGet($"{defaultPath}/simulate", () => $"Successfull request for destination {destination} from {app} app\n");
           

至此,我们完成了最小路由 API,使我们能够测试我们的 API 网关。现在,为了更方便起见,我们将使用此路由 API 创建一个 docker compose 文件,我们将能够根据需要复制和操作部署,但首先我们需要发布此 API:

dotnet publish --os linux --arch arm64 -p:PublishProfile=DefaultContainer
           

如果您在 Windows 或 Linux 中运行此代码,请删除 arch 指令。此命令将在 docker 守护程序中发布 docker 映像

之后,我们可以创建具有以下规范的 docker compose 文件:

services:
 fooapp:
 image: simple-routing-app:latest
 restart: always
 environment:
 - ROOT_PATH=/api/foo
 - APP_NAME=foo
 - DESTINATION=destination1
 ports:
 - 8080:80
           

现在我们可以开始构建我们的 API 网关了,首先我们需要创建另一个 dotnet API 并将 YARP 库添加到这个 API:

dotnet new web -o Gateway 
dotnet add package Yarp.ReverseProxy
           

要在我们的项目中配置反向代理,我们需要在配置中添加以下服务:

public void ConfigureServices(IServiceCollection services) 
{ 
 services.AddReverseProxy(); 
} 
public void Configure(IApplicationBuilder app) 
{ 
 app.UseRouting(); 
 app.UseEndpoints(); 
}
           

现在我们需要添加一些路由配置,为此我们有很多选择:

  1. 将名为 ReverseProxy 的配置添加到我们的appsettings.json
  2. 创建 InMemoryConfigProvider
  3. 创建自定义 IProxyConfigProvider

我们将选择第三种方式,因为这将是下一章的钩子,以及我们希望如何最接近真实情况,对我来说,这是最好的方法。

为此,我们需要创建一个名为“CustomProxyConfigProvider”的新类,该类需要扩展接口 IProxyConfigProvider,该接口实现了 GetConfig() 方法和扩展 IProxyConfig 的“CustomMemoryConfig”类。

public class CustomProxyConfigProvider: IProxyConfigProvider
{
private CustomMemoryConfig _config;

public IProxyConfig GetConfig() => _config;
}

public class CustomMemoryConfig: IProxyConfig
{
private readonly CancellationTokenSource _cts = new CancellationTokenSource();

public CustomMemoryConfig(IReadOnlyList<RouteConfig> routes, IReadOnlyList<ClusterConfig> clusters)
 {
 Routes = routes;
 Clusters = clusters;
 ChangeToken = new CancellationChangeToken(_cts.Token);
 }

public IReadOnlyList<RouteConfig> Routes { get; }
public IReadOnlyList<ClusterConfig> Clusters { get; }
public IChangeToken ChangeToken { get; }

internal void SignalChange()
 {
 _cts.Cancel();
 }
}
           

为了将请求路由到我们的应用程序,我们需要向我们的 API Gateway 提供一些配置,YARP 使用由路由和集群组成的标准配置,我们将在 CustomProxyConfigProvider 中创建一个方法来创建此配置:

public void LoadConfig() 
{
var routeConfig = new RouteConfig 
 { 
 RouteId = "route1",
 ClusterId = "cluster1", 
 Match = new RouteMatch
 {
 Path = "/api/foo/{**catch-all}"
 }
 };
var clusterConfig = new ClusterConfig
 {
 ClusterId = "cluster1",
 LoadBalancingPolicy = LoadBalancingPolicy.RoundRobin,
 Destinations = new Dictionary<string, DestinationConfig>()
 {
"destination1", new DestinationConfig
 {
 Address = "http://localhost:8080"
 }
 }
 }

var routes = new List<RouteConfig>();
 routes.add(routeConfig);
var clusters = new List<ClusterConfig>();
 clusters.add(clusterConfig);

 _config = new CustomMemoryConfig(routes, clusters);
}
           

我们需要将此提供程序添加到 Startup 类的配置中:

public void ConfigureServices(IServiceCollection services) 
{ 
 services 
 .AddSingleton<IProxyConfigProvider>(new CustomProxyConfigProvider()) 
 .AddReverseProxy(); 
}
           

通过此配置,我们可以运行应用程序并测试网关的路由,因此首先,我们将运行本文开头创建的 docker compose:

docker compose up -d
           

并运行我们的 Gateway 项目:

dotnet run .
           

现在,我们已经运行了应用程序和已配置的 API 网关,我们可以调用来测试路由,当我运行网关时,请选择要公开的端口 5025:

curl http://localhost:5025/api/foo/simulate
           

这将响应以下消息:

Successfull request for destination destination1 from foo app
           

在本章的最后,我们创建了一个简单的应用程序,并对我们的网关进行了简单的配置,并查看通过我们的 API 网关路由的请求。在下一章中,我们将创建控制平面,使我们的配置能够在运行时更改并自定义我们的配置。

如果你喜欢我的文章,请给我一个赞!谢谢

继续阅读