资讯动态

YARP 反向代理代码扩展实战:动态内存配置与自定义管线步骤(ReverseProxy.Code.Sample 深度解析)

发布时间:2026/9/16 13:55:30 来源:尧图企业网站定制
YARP 反向代理代码扩展实战动态内存配置与自定义管线步骤ReverseProxy.Code.Sample 深度解析【免费下载链接】reverse-proxyA toolkit for developing high-performance HTTP reverse proxy applications.项目地址: https://gitcode.com/GitHub_Trending/re/reverse-proxy导读本篇文章围绕 YARPYet Another Reverse Proxy开源仓库中的samples/ReverseProxy.Code.Sample示例深入讲解两种最常见的纯代码扩展方式从代码动态提供路由与目标配置借助InMemoryConfigProvider内存配置提供器以及向代理请求管线中插入自定义处理步骤通过MapReverseProxy自定义管线并读写IReverseProxyFeature。读完本文你将掌握如何在完全脱离配置文件的前提下用 C# 代码以快照模型原子地更新代理路由并在不修改任何内置实现的情况下自定义目标Destination筛选逻辑满足灰度、调试分流等真实场景需求。示例概览两个核心扩展点示例的完整说明见 samples/ReverseProxy.Code.Sample/README.md核心实现集中在单个文件 Program.cs 中。它演示了 YARP 的两个扩展维度动态配置Dynamic configuration from code路由与集群的配置不再来自appsettings.json等配置文件而是在代码中直接构造RouteConfig[]与ClusterConfig[]交给内存配置提供器并由一个/update端点触发运行时刷新。自定义管线步骤Custom pipeline step通过MapReverseProxy重载自定义请求处理管线插入一个MyCustomProxyStep中间件根据请求头Debug: true过滤集群中可用的目标集合。示例工程通过项目引用方式依赖 YARP 核心库见 ReverseProxy.Code.Sample.csprojProjectReference指向src/ReverseProxy/Yarp.ReverseProxy.csproj其appsettings.json仅保留常规日志配置不含任何代理路由定义这从侧面印证了配置完全由代码提供的定位。扩展点一从代码动态提供配置为什么需要代码化配置YARP 默认支持从配置文件如appsettings.json读取ReverseProxy节并绑定为路由与集群。但现实场景中路由规则、目标地址往往来自数据库、控制平面如 K8s Ingress 控制器、管理后台或其他远程系统。示例文档明确指出YARP 的可扩展性让开发者从任何数据源获取数据再以对象列表的形式交给代理这正是InMemoryConfigProvider的用武之地。用代码构造 RouteConfig 与 ClusterConfig示例中通过两个局部函数构造配置对象GetRoutes()返回RouteConfig[]每项包含必填的RouteId、Match路由匹配规则以及可选的ClusterId。示例使用Path {**catch-all}作为捕获所有路径的通配匹配并在每次调用时用Random.Shared.Next()生成新的RouteId——这样每次刷新都会产生一条新路由便于验证配置更新确实生效。GetClusters()返回ClusterConfig[]定义集群cluster1及其目标集合destination1https://example.com与debugdestination1https://bing.com后者携带Metadata { debug: true }供自定义管线步骤识别。从源码看RouteConfig见 RouteConfig.cs还支持Order路由优先级数值小者优先、AuthorizationPolicy、RateLimiterPolicy、OutputCachePolicy、Timeout、MaxRequestBodySize、Metadata、Transforms等丰富属性ClusterConfig见 ClusterConfig.cs则支持LoadBalancingPolicy、SessionAffinity、HealthCheck、HttpClient、HttpRequest等集群级策略。这些属性在代码配置与文件配置中完全等价可以按需自由组合。InMemoryConfigProvider内存配置提供器配置对象构造完成后通过依赖注入接入代理builder.Services.AddReverseProxy() .LoadFromMemory(GetRoutes(), GetClusters());LoadFromMemory是定义在 InMemoryConfigProviderExtensions.cs 中的扩展方法其实现把InMemoryConfigProvider注册为单例并同时注册为IProxyConfigProvider服务。也就是说InMemoryConfigProvider实例在代理的整个生命周期内被复用后续对它的Update调用都会驱动代理重新加载配置。InMemoryConfigProvider的核心实现位于 InMemoryConfigProvider.cs其中有两个关键机制变更令牌Change TokenIProxyConfig接口见 IProxyConfig.cs包含Routes、Clusters、RevisionId与ChangeToken。InMemoryConfig内部持有一个CancellationTokenSource将其包装为CancellationChangeToken暴露出去当一批配置变更完成时调用SignalChange()即_cts.Cancel()通知代理该快照已过期请取新快照。原子快照替换_config字段被标记为volatileUpdateInternal使用Interlocked.Exchange一次性替换整个快照引用随后对旧快照调用SignalChange()。这意味着新旧配置的切换是原子的不会出现读了一半新配置的中间状态。快照模型与 15 秒建议示例文档特别强调YARP 对配置采用快照snapshot模型变更以原子动作应用只影响变更之后到达的请求已在处理中的请求会继续使用其接收时刻的配置快照完成整个处理流程不会被中途换轨。ProxyConfigManager见 ProxyConfigManager.cs负责监听各IProxyConfigProvider的变更令牌并在变更后重建内部状态。快照处理过程中一个重要步骤是在 ASP.NET 中构建经过优化的路由表route table这是一项 CPU 密集型操作。因此示例文档明确建议配置更新信号的触发频率不要高于每 15 秒一次以免高频率的配置变更导致路由表反复重建拖累代理整体性能。运行时刷新/update 端点为了直观演示运行中更新配置示例注册了一个特殊端点app.Map(/update, context { context.RequestServices.GetRequiredServiceInMemoryConfigProvider().Update(GetRoutes(), GetClusters()); return Task.CompletedTask; });向/update发起任意 HTTP 请求即会通过 DI 拿到同一个InMemoryConfigProvider实例调用其Update方法见 InMemoryConfigProvider.cs。由于每次GetRoutes()都会生成新的随机RouteId路由表会随每次/update请求而重建。在实际项目中这里可以替换为从数据库拉取最新路由与目标列表并调用Update即可实现完全代码化的热更新。扩展点二自定义管线步骤默认的七阶段请求管线示例文档给出了 YARP 处理每个请求时的默认管线阶段将请求路径映射到路由与目标集群Mapping the request path to a route and cluster根据请求中已有的会话亲和Session Affinity头预分配服务器过滤掉不健康的服务器Filtering destinations在剩余服务器之间按负载等进行负载均衡按需保存会话亲和信息按需转换请求/响应头将请求/响应代理到目标服务器YARP 允许开发者在任意位置插入自定义阶段或用自定义实现替换内置阶段。从源码看默认管线由MapReverseProxy(this IEndpointRouteBuilder endpoints)重载组装见 ReverseProxyIEndpointRouteBuilderExtensions.cs依次是会话亲和中间件UseSessionAffinity→ 负载均衡中间件UseLoadBalancing→ 被动健康检查UsePassiveHealthChecks而带configureApp参数的重载同文件第 39-55 行则固定以ProxyPipelineInitializerMiddleware开头、以LimitsMiddleware与ForwarderMiddleware收尾中间部分完全由开发者自由编排。MapReverseProxy 自定义管线示例采用带配置回调的重载app.MapReverseProxy(proxyPipeline { proxyPipeline.Use(MyCustomProxyStep); proxyPipeline.UseSessionAffinity(); proxyPipeline.UseLoadBalancing(); });这里的MyCustomProxyStep被插在管线最前面紧随其后的UseSessionAffinity()与UseLoadBalancing()是自定义管线时必须保留的两个中间件若业务需要它们否则会话亲和与负载均衡逻辑不会执行。示例注释也明确提醒了这一点。IReverseProxyFeature管线步骤的数据通道自定义步骤与内置中间件之间通过 ASP.NET Core 的Feature 机制交换数据。ProxyPipelineInitializerMiddleware见 ProxyPipelineInitializerMiddleware.cs在管线开头把当前请求的路由、集群与目标集合封装进ReverseProxyFeature并写入HttpContext.Features。IReverseProxyFeature接口见 IReverseProxyFeature.cs暴露了Route当前请求命中的路由模型Cluster当前请求所属集群模型AllDestinations集群的全部目标AvailableDestinations可读写可处理当前请求的目标集合初始为排除了不健康目标后的全部目标ProxiedDestination实际被代理到的目标。关键点在于AvailableDestinations是可写的——后续的LoadBalancingMiddleware见 LoadBalancingMiddleware.cs正是从AvailableDestinations中挑选最终目标若集合为空则记录NoAvailableDestinations日志并交由后续中间件处理若只有一个则直接选用否则按集群配置的负载均衡策略默认PowerOfTwoChoices选择。因此在负载均衡之前改写AvailableDestinations就能天然改变最终代理去向——这正是自定义目标筛选的标准切入点。MyCustomProxyStep 实现详解Task MyCustomProxyStep(HttpContext context, FuncTask next) { var useDebugDestinations context.Request.Headers.TryGetValue(DEBUG_HEADER, out var headerValues) headerValues.Count 1 headerValues[0] DEBUG_VALUE; var availableDestinationsFeature context.Features.GetIReverseProxyFeature(); var filteredDestinations new ListDestinationState(); foreach (var d in availableDestinationsFeature.AvailableDestinations) { if (d.DestinationId.Contains(debug) useDebugDestinations) { filteredDestinations.Add(d); } } availableDestinationsFeature.AvailableDestinations filteredDestinations; return next(); }其运行逻辑为读取请求头若请求携带唯一的Debug: true头则useDebugDestinations true表示本次请求希望命中调试目标否则为false。读取代理特性通过context.Features.GetIReverseProxyFeature()拿到当前请求的代理数据。过滤目标遍历AvailableDestinations按DestinationId是否包含debug与请求头布尔值是否一致来决定保留或剔除DestinationId定义见 DestinationState.cs。即带Debug: true头时只保留debugdestination1不带时只保留destination1实现调试流量打向带 debug 元数据的目标常规流量走正常目标的分流效果。写回结果将过滤后的列表赋回AvailableDestinations供后续会话亲和、负载均衡中间件消费。继续管线务必调用next()将请求传递给下一环节——注释也强调这是进入代理管线下一步的关键。需要说明的是示例代码中过滤依据是DestinationId.Contains(debug)并在注释中注明应替换为元数据查找但当前此处未正确暴露代码见 Program.cs。也就是说从示例设计意图看过滤应基于ClusterConfig中为debugdestination1配置的Metadata { debug: true }若希望严格按元数据过滤可从DestinationState.Model类型DestinationModel含Config读取对应DestinationConfig.Metadata。在实际落地时推荐以Metadata作为判定依据避免依赖命名约定。完整程序串讲与运行验证示例 Program.cs 的完整启动流程可归纳为创建WebApplicationBuilder注册控制器并调用AddReverseProxy().LoadFromMemory(GetRoutes(), GetClusters())注入内存配置Build()后注册/update刷新端点以自定义回调调用MapReverseProxy插入MyCustomProxyStep并显式追加会话亲和与负载均衡中间件Run()启动。运行该示例需要 .NET SDKTFMs.props定义了$(ReleaseTFMs)目标框架进入示例目录执行dotnet run即可启动。可以按如下方式验证两个扩展点验证自定义管线向https://localhost:端口/发送请求不带Debug头时流量走向destination1https://example.com带上Debug: true头时流量走向debugdestination1https://bing.com。验证动态配置观察/update端点触发Update后代理以原子快照方式应用新路由表由于每次都会生成新RouteId可在日志或路由命中行为上观察到更新已生效。需要提醒的是示例集群中的destination1与debugdestination1是指向外部站点example.com / bing.com的占位地址实际使用时请替换为自己的下游服务地址同时应遵守上文提到的15 秒最小更新间隔建议。相关文件索引文件说明samples/ReverseProxy.Code.Sample/README.md示例官方说明文档本篇文章的主要依据samples/ReverseProxy.Code.Sample/Program.cs示例完整实现动态配置 自定义管线步骤src/ReverseProxy/Configuration/InMemoryConfigProvider.cs内存配置提供器原子快照替换与变更令牌实现src/ReverseProxy/Configuration/InMemoryConfigProviderExtensions.csLoadFromMemory扩展方法单例注册与IProxyConfigProvider桥接src/ReverseProxy/Configuration/IProxyConfig.cs配置快照接口Routes/Clusters/RevisionId/ChangeTokensrc/ReverseProxy/Configuration/RouteConfig.cs路由配置模型含匹配、策略、转换等全部可选字段src/ReverseProxy/Configuration/ClusterConfig.cs集群配置模型含负载均衡、会话亲和、健康检查等src/ReverseProxy/Routing/ReverseProxyIEndpointRouteBuilderExtensions.csMapReverseProxy两个重载默认管线与自定义管线组装src/ReverseProxy/Model/ProxyPipelineInitializerMiddleware.cs管线初始化向HttpContext.Features写入IReverseProxyFeaturesrc/ReverseProxy/Model/IReverseProxyFeature.cs代理特性接口AvailableDestinations可读写src/ReverseProxy/LoadBalancing/LoadBalancingMiddleware.cs负载均衡中间件消费AvailableDestinations并选定最终目标总结通过ReverseProxy.Code.Sample可以清晰地看到 YARP 代码扩展性的两个支柱以InMemoryConfigProvider为代表的快照式动态配置让代理的路由与目标可以来自任意数据源并以原子方式热更新以IReverseProxyFeature为数据通道的自定义管线步骤让开发者能在不触碰内置实现的前提下精确干预每个请求的目标选择与处理流程。结合仓库中 InMemoryConfigProvider.cs 的Interlocked.Exchange 变更令牌实现以及 ReverseProxyIEndpointRouteBuilderExtensions.cs 对管线的固定首尾编排读者可以在此基础上继续探索IProxyConfigFilter、IConfigChangeListener、会话亲和策略替换等更深的扩展点构建完全定制化的高性能反向代理。【免费下载链接】reverse-proxyA toolkit for developing high-performance HTTP reverse proxy applications.项目地址: https://gitcode.com/GitHub_Trending/re/reverse-proxy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价