.NET 反向代理 YARP 自定義配置提供程式(Configuration Providers)
介紹
基本 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(); }); }
- 記一次批量更新整型型別的列 → 探究 UPDATE 的使用細節
- 編碼中的Adapter,不僅是一種設計模式,更是一種架構理念與解決方案
- 執行緒池底層原理詳解與原始碼分析
- 30分鐘掌握 Webpack
- 線性迴歸大結局(嶺(Ridge)、 Lasso迴歸原理、公式推導),你想要的這裡都有
- Django 之路由層
- 【前端必會】webpack loader 到底是什麼
- day42-反射01
- 中心化決議管理——雲端分析
- HashMap底層原理及jdk1.8原始碼解讀
- 詳解JS中 call 方法的實現
- 列印 Logger 日誌時,需不需要再封裝一下工具類?
- 初識設計模式 - 代理模式
- 設計模式---享元模式
- 密碼學奇妙之旅、01 CFB密文反饋模式、AES標準、Golang程式碼
- [ML從入門到入門] 支援向量機:從SVM的推導過程到SMO的收斂性討論
- 從應用訪問Pod元資料-DownwardApi的應用
- Springboot之 Mybatis 多資料來源實現
- Java 泛型程式設計
- CAS核心思想、底層實現