.NET 反向代理 YARP 自定義設定提供程式(Configuration Providers)

2022-09-25 06:01:24

介紹

  基本 Yarp 範例顯示從 appsettings.json 載入的代理設定。相反,代理設定可以從您選擇的源以程式設計方式載入。您可以通過提供幾個實現 IProxyConfigProvider 和 IProxyConfig 的類來做到這一點。

  可以使用設定過濾器在載入序列期間修改設定。

結構

  IProxyConfigProvider 有一個方法應該返回一個 IProxyConfig 範例。 IProxyConfig 具有當前路由和叢集的列表,以及在此資訊過期並應重新載入時通知代理,這將導致再次呼叫(GetConfig()IChangeTokenGetConfig())

路線

  路由部分是命名路由的無序集合。路由包含匹配項及其相關設定。一條路線至少需要以下欄位:

  RouteId - 一個唯一的名稱

  ClusterId - 指叢集部分中的條目名稱。

  Match - 包含 Hosts 陣列或 Path 模式字串。 Path 是一個 ASP.NET Core 路由模板,可以按照此處的說明進行定義。

  可以在每個路由條目上設定檔頭、授權、CORS 和其他基於路由的策略。

  代理將應用給定的匹配條件和策略,然後將請求傳遞給指定的叢集。

叢集

  叢集部分是命名叢集的無序集合。叢集主要包含命名目的地及其地址的集合,其中任何一個都被認為能夠處理給定路由的請求。代理將根據路由和叢集設定處理請求以選擇目的地。

生命週期

啟動

  應該在 DI 容器中註冊為單例。啟動時,代理將解析此範例並呼叫 .在第一次呼叫時,提供者可以選擇:IProxyConfigProviderGetConfig()

  如果提供者出於任何原因無法生成有效的代理設定,則丟擲異常。這將阻止應用程式啟動。

  在載入設定時同步阻塞。這將阻止應用程式啟動,直到有效的路線資料可用。

  或者,它可以選擇在後臺載入設定時返回一個空範例。提供者將需要在設定可用時觸發(IProxyConfigIChangeToken)

  代理將驗證給定的設定,如果它無效,將引發異常,阻止應用程式啟動。提供者可以通過使用 IConfigValidator 來預先驗證路由和叢集並採取它認為適當的任何操作(例如排除無效條目)來避免這種情況。

原子性

  提供給代理的設定物件和集合應該是唯讀的,一旦通過 .GetConfig() 傳遞給代理就不能修改

重新載入

  如果支援,一旦代理處理了初始設定集,它將使用此令牌註冊回撥。如果提供者不支援回撥,則每 5 分鐘輪詢一次(IChangeTokenActiveChangeCallbacksHasChanged)

  1、當提供者想要為代理提供新設定時,它應該:

  (1)在後臺載入該設定。

    a. 路由和叢集物件是不可變的,因此必須為任何新資料建立新範例。

    b. 可以重新使用未更改的路由和叢集的物件,或者可以建立新的範例 - 將通過區分它們來檢測更改。

  (2)可選地使用 IConfigValidator 驗證設定,然後才從先前的範例發出新資料可用的訊號。代理將再次呼叫以檢索新資料(IChangeTokenIProxyConfigGetConfig())

  2、重新載入設定與第一次設定載入時存在重要差異。

  (1)新設定將與當前設定不同,並且只會更新修改後的路由或叢集。更新將自動應用,並且只會影響新請求,而不影響當前正在進行的請求。

  (2)重新載入過程中的任何錯誤都將被記錄並抑制。應用程式將繼續使用上次已知的正確設定。

  (3)如果丟擲代理將無法監聽未來的變化,因為 s 是一次性的(GetConfig()IChangeToken)

  驗證並應用新設定後,代理將使用新的 .請注意,如果連續發出多次重新載入訊號,代理可能會跳過一些並在準備好後立即載入下一個可用設定。每個都包含完整的設定狀態,因此不會丟失任何內容(IChangeTokenIProxyConfig)

多個設定源

  從 1.1 開始,YARP 支援從多個來源載入代理設定。 多個可以註冊為單例服務,所有將被解析和組合。 源可以是相同或不同的型別,例如 IConfiguration 或 InMemory。 路由可以參照其他來源的叢集。 請注意,不支援為給定路由或叢集合並來自不同來源的部分設定(IProxyConfigProvider)

services.AddReverseProxy()
        .LoadFromConfig(Configuration.GetSection("ReverseProxy1"))
        .LoadFromConfig(Configuration.GetSection("ReverseProxy2"));

或者

services.AddReverseProxy()
        .LoadFromMemory(routes, clusters)
        .LoadFromConfig(Configuration.GetSection("ReverseProxy"));

Example

  以下是手動載入路由和叢集的範例(IProxyConfigProvider)

using System.Collections.Generic;
using System.Threading;
using Microsoft.Extensions.Primitives;
using Yarp.ReverseProxy.Configuration;

namespace Microsoft.Extensions.DependencyInjection
{
    public static class InMemoryConfigProviderExtensions
    {
        public static IReverseProxyBuilder LoadFromMemory(this IReverseProxyBuilder builder, IReadOnlyList<RouteConfig> routes, IReadOnlyList<ClusterConfig> clusters)
        {
            builder.Services.AddSingleton<IProxyConfigProvider>(new InMemoryConfigProvider(routes, clusters));
            return builder;
        }
    }
}

namespace Yarp.ReverseProxy.Configuration
{
    public class InMemoryConfigProvider : IProxyConfigProvider
    {
        private volatile InMemoryConfig _config;

        public InMemoryConfigProvider(IReadOnlyList<RouteConfig> routes, IReadOnlyList<ClusterConfig> clusters)
        {
            _config = new InMemoryConfig(routes, clusters);
        }

        public IProxyConfig GetConfig() => _config;

        public void Update(IReadOnlyList<RouteConfig> routes, IReadOnlyList<ClusterConfig> clusters)
        {
            var oldConfig = _config;
            _config = new InMemoryConfig(routes, clusters);
            oldConfig.SignalChange();
        }

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

            public InMemoryConfig(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();
            }
        }
    }
}

  下面是它在 Startup.cs 中的呼叫方式:

public void ConfigureServices(IServiceCollection services)
{
    var routes = new[]
    {
        new RouteConfig()
        {
            RouteId = "route1",
            ClusterId = "cluster1",
            Match = new RouteMatch
            {
                Path = "{**catch-all}"
            }
        }
    };
    var clusters = new[]
    {
        new ClusterConfig()
        {
            ClusterId = "cluster1",
            Destinations = new Dictionary<string, DestinationConfig>(StringComparer.OrdinalIgnoreCase)
            {
                { "destination1", new DestinationConfig() { Address = "https://example.com" } }
            }
        }
    };

    services.AddReverseProxy()
        .LoadFromMemory(routes, clusters);
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseRouting();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapReverseProxy();
    });
}

 

原文連結:https://www.cnblogs.com/ysmc/p/16727084.html