Welcome to YARP - 2.3 配置功能 - 配置过滤器(Configuration Filters)

目录

Welcome to YARP - 1.认识YARP并搭建反向代理服务

Welcome to YARP - 2.配置功能

Welcome to YARP - 3.负载均衡

Welcome to YARP - 4.限流

Welcome to YARP - 5.身份验证和授权

Welcome to YARP - 6.压缩、缓存

Welcome to YARP - 7.目标健康检查

Welcome to YARP - 8.分布式跟踪

哈哈哈,第一篇文章还说,只规划了8篇文章,写到配置功能的时候发现东西还是挺多的,还是拆分成小章节来说吧。目前成了10篇了—_—。写之前觉得配置功能应该没什么东西可讲,结果写着写着都想讲一嘴。然后就越写越多,大家看的时候可以选择性的跳过。

介绍

如果有同学不知道YARP是什么,YARP有哪些功能,或者对配置没有基本概念的同学请看前几篇文章,接下来这篇文章主要讲解YARP的配置功能的第三小章节:配置过滤器

配置过滤器(Configuration Filters)

YARProutes, clustersdestinations 的配置可以通过配置文件或其他配置提供者加载过来。

而配置过滤器可用于在验证应用原始输入(原始配置)之前对其进行修改。

加载配置 => 配置过滤器 => 验证配置 => 应用配置

过滤器可用于多种目的,例如:

  • 使用来自其他源(如部署环境)的数据补充配置字段
  • 应用系统默认值
  • 应用通用设置并强制实施策略
  • 替换占位符值 (下面的演示就是此场景)
  • 规范化和纠错

AddConfigFilter

配置过滤器使用 AddConfigFilter API 在依赖项注入系统中注册。可以添加任意数量的唯一过滤器,并将按添加顺序应用

using YARP.Configuration.ConfigFilter;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddReverseProxy()
                .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"))//加载配置
                .AddConfigFilter<CustomConfigFilter>();//注册配置过滤器

var app = builder.Build();

// Configure the HTTP request pipeline.
app.MapReverseProxy();

app.Run();

首先我们创建一个CustomConfigFilter类并继承 IProxyConfigFilter 接口,然后我们去实现ConfigureClusterAsync方法和ConfigureRouteAsync方法。在这两个方法中对路由信息和集群信息进行拦截和自定义处理。

每次加载或重新加载配置时,都会为每个路由和集群调用过滤器。可以选择返回未修改的原始输入或修改后的副本。

此示例把地址替换为环境变量中的目标地址,并将路由的 Order 字段设置为 1

using System.Text.RegularExpressions;
using Yarp.ReverseProxy.Configuration;

namespace YARP.Configuration.ConfigFilter;

public class CustomConfigFilter : IProxyConfigFilter
{
    // 用于匹配文本中的双花括号{{}}包围的单词(字母数字字符)
    private readonly Regex _exp = new("\\{\\{(\\w+)\\}\\}");

    // 集群的配置过滤器,将依次传递给每个集群,它应该按原样返回,或者 克隆并创建具有更新更改的新版本
    // 此示例查看目标地址(destination addresses),任何形式{{key}}都将被匹配到,并用此key获取环境变量里对应的value
    // 作为环境变量。当托管在Azure等中时,这很有用,因为它能够以简单的方式替换
    public ValueTask<ClusterConfig> ConfigureClusterAsync(ClusterConfig origCluster, CancellationToken cancel)
    {
        // 每个集群都有一个 destination 字典,它是只读的,所以我们将用更新创建一个 destination 字典
        var newDests = new Dictionary<string, DestinationConfig>(StringComparer.OrdinalIgnoreCase);

        foreach (var d in origCluster.Destinations)
        {
            var origAddress = d.Value.Address;
            if (_exp.IsMatch(origAddress))
            {
                // 用先前定义的正则表达式_exp来匹配字符串,然后提取第一个匹配的结果的捕获组(Group)中索引为1的值: baidu。
                var lookup = _exp.Matches(origAddress)[0].Groups[1].Value;
                // 根据key(baidu):获取 value (https://www.baidu.com)
                var newAddress = Environment.GetEnvironmentVariable(lookup);

                if (string.IsNullOrWhiteSpace(newAddress))
                {
                    throw new ArgumentException($"Configuration Filter Error: Substitution for '{lookup}' in cluster '{d.Key}' not found as an environment variable.");
                }

                // c# 9 "with" 语法: 克隆并初始化 record
                var modifiedDest = d.Value with { Address = newAddress };
                newDests.Add(d.Key, modifiedDest);
            }
            else
            {
                newDests.Add(d.Key, d.Value);
            }
        }

        return new ValueTask<ClusterConfig>(origCluster with { Destinations = newDests });
    }

    public ValueTask<RouteConfig> ConfigureRouteAsync(RouteConfig route, ClusterConfig? cluster, CancellationToken cancel)
    {
        // Example: 不要让基于配置的路由优先于基于代码的路由。
        // 数字越低,优先级越高。代码路由默认为0。
        if (route.Order.HasValue && route.Order.Value < 1)
        {
            return new ValueTask<RouteConfig>(route with { Order = 1 });
        }

        return new ValueTask<RouteConfig>(route);
    }
}

配置如下:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ReverseProxy": {
    "Routes": {
      "route1": {
        "ClusterId": "cluster1",
        "Match": {
          "Path": "{**catch-all}"
        }
      }
    },
    "Clusters": {
      "cluster1": {
        "Destinations": {
          "cluster1/destination1": {
            // 以下值将由regex找到,并作为环境变量查找
            "Address": "{{baidu}}"
          }
        }
      }
    }
  }
}

launchSettings.json文件中环境变量设置如下:

"environmentVariables": {
	"ASPNETCORE_ENVIRONMENT": "Development",
    "baidu": "https://www.baidu.com"
}

总结

配置过滤器就结束了,我们通过实现IProxyConfigFilter 接口对配置进行替换,配置文件中写的是占位符{{baidu}},用它当作key,环境变量里才是我们的真实地址,通过配置过滤器去拦截并处理替换成真实的地址。这对于敏感数据及其有用。代码示例已上传GitHub:YARP.Configuration.ConfigFilter

这篇文章就到这里,下一篇我们介绍 YARP 的负载均衡功能。

posted @ 2023-11-03 00:23  coding-y  阅读(244)  评论(0编辑  收藏  举报