当前位置: 首页 > news >正文

ABP VNext + Microsoft YARP:自定义反向代理与请求路由

ABP VNext + Microsoft YARP:自定义反向代理与请求路由 ☁️


📚 目录

  • ABP VNext + Microsoft YARP:自定义反向代理与请求路由 ☁️
    • 一、引言 🎉
    • 二、环境与依赖 🛠️
    • 三、项目骨架与启动配置 📁
      • 3.1 目录结构
      • 3.2 配置加载流程
      • 3.3 Program.cs 高层结构
    • 四、关键配置文件详解 ⚙️
    • 五、模块化服务注册扩展 🧩
    • 六、模块化中间件管道扩展 🛣️
      • 6.1 请求管道流程图
    • 七、熔断与重试策略(Polly)🔥
    • 八、请求限流 🎯
    • 九、与 ABP 认证体系深度集成 🔒
    • 十、自定义中间件与扩展点 🛠️
    • 十一、日志与可观测性 📈
    • 十二、架构全景图 🏗️
    • 十三、端到端演示与可复现脚本 🚀
      • 13.1 Docker Compose
      • 13.2 k6 压测脚本
      • 13.3 Postman Collection


一、引言 🎉

✨ TL;DR

  • 基于 ABP VNext + Microsoft YARP 构建生产级 API 网关;
  • 支持动态路由热加载、熔断(Circuit Breaker)、指数退避重试⚡;
  • IP/ClientID 限流、路由级授权🔒、转发头、CORS 安全策略;
  • 集成 YARP Active Health Check、Prometheus 指标📊、Serilog 日志;
  • 提供 Docker Compose 与 k6 脚本,一键复现🚀。

📚 背景与动机
在微服务架构中,网关负责「统一入口」「流量控制」「安全边界」「可观测性」。ABP VNext 6.x 官方推荐使用 YARP 替代 Ocelot,其高吞吐、低延迟、配置同源与可扩展性完美契合生产环境需求。


二、环境与依赖 🛠️

  • 平台:.NET 6 + ABP VNext 6.x

  • 关键 NuGet 包

    <PackageReference Include="Microsoft.ReverseProxy" Version="1.1.0-preview.8.21451.2" />
    <PackageReference Include="Polly.Extensions.Http" Version="3.0.0" />
    <PackageReference Include="AspNetCoreRateLimit" Version="4.3.1" />
    <PackageReference Include="Volo.Abp.AspNetCore.Authentication.JwtBearer" Version="6.4.0" />
    <PackageReference Include="prometheus-net.AspNetCore" Version="5.0.1" />
    <PackageReference Include="Serilog.AspNetCore" Version="7.0.0" />
    
  • 容器化说明
    配置支持环境变量、Kubernetes ConfigMap/Secret、Docker Compose 覆盖,免重建镜像。


三、项目骨架与启动配置 📁

3.1 目录结构

Gateway/
├─ Gateway.csproj
├─ Program.cs
├─ appsettings.json
├─ appsettings.Production.json
└─ ProxyConfig/├─ Routes.json└─ Clusters.json
Services/            // 后端微服务
docker-compose.yml

3.2 配置加载流程

读取 appsettings.json
读取 ProxyConfig/*.json
构建 IConfiguration
注册服务与中间件
启动 WebHost

3.3 Program.cs 高层结构

var builder = WebApplication.CreateBuilder(args);// 1. Serilog 日志
builder.Host.UseSerilog((ctx, lc) => lc.ReadFrom.Configuration(ctx.Configuration));// 2. 配置热加载
builder.Configuration.AddJsonFile("appsettings.json", false, true).AddJsonFile("ProxyConfig/Routes.json", true, true).AddJsonFile("ProxyConfig/Clusters.json", true, true).AddEnvironmentVariables();// 3. 模块化服务注册
builder.Services.AddGatewayServices(builder.Configuration);var app = builder.Build();// 4. 模块化管道配置
app.UseGatewayPipeline();app.Run();

四、关键配置文件详解 ⚙️

// appsettings.json
{"AuthServer": {"Authority": "https://auth.mycompany.com"},"Yarp": {"Routes": [],    // 从 ProxyConfig/*.json 加载"Clusters": {}},"IpRateLimiting": {"EnableEndpointRateLimiting": true,"HttpStatusCode": 429,"EndpointWhitelist": [ "/health" ],"GeneralRules": [{ "Endpoint": "/orders/*", "Period": "1s", "Limit": 5 }]},"Serilog": {"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.Elasticsearch" ],"WriteTo": [{ "Name": "Console" },{"Name": "Elasticsearch","Args": {"nodeUris": "http://elasticsearch:9200","indexFormat": "gateway-logs-{0:yyyy.MM.dd}"}}]}
}
// ProxyConfig/Routes.json
{"Routes": [{"RouteId": "orderRoute","ClusterId": "orderCluster","Match": { "Path": "/orders/{**catch-all}" },"Metadata": { "AuthorizationPolicy": "AdminOnly" }}]
}
// ProxyConfig/Clusters.json
{"Clusters": {"orderCluster": {"LoadBalancing": { "Mode": "RoundRobin" },"HealthCheck": {"Active": {"Enabled": true,"Interval": "00:00:10","Timeout": "00:00:02","Path": "/health"}},"Destinations": {"instance1": { "Address": "http://ordersvc1:80/" },"instance2": { "Address": "http://ordersvc2:80/" }}}}
}

五、模块化服务注册扩展 🧩

public static class GatewayServiceExtensions
{public static IServiceCollection AddGatewayServices(this IServiceCollection services, IConfiguration config){// 1. 转发头(真实客户端 IP)services.Configure<ForwardedHeadersOptions>(opts =>{opts.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;// 若使用 Service Mesh,可配置 KnownProxies/KnownNetworks});// 2. CORS 安全策略(白名单域)services.AddCors(opts => opts.AddPolicy("GatewayCors", p =>p.WithOrigins("https://app.mycompany.com").AllowAnyMethod().AllowAnyHeader()));// 3. 限流(In-Memory 存储)services.AddMemoryCache();services.Configure<IpRateLimitOptions>(opts => config.GetSection("IpRateLimiting").Bind(opts));services.AddInMemoryRateLimiting();services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();services.AddSingleton<IClientResolveContributor, ClaimClientIdResolveContributor>();// 4. YARP + 转发 Authorizationservices.AddReverseProxy().LoadFromConfig(config.GetSection("Yarp")).AddTransforms(t => t.AddRequestTransform(ctx =>{if (ctx.HttpContext.Request.Headers.TryGetValue("Authorization", out var token))ctx.ProxyRequest.Headers.Add("Authorization", token.ToArray());return ValueTask.CompletedTask;})).AddPolicyManager();  // Polly 策略统一注入// 5. ABP JWT 鉴权services.AddAuthentication().AddAbpJwtBearer(options =>{options.Authority = config["AuthServer:Authority"];options.Audience = "GatewayAPI";options.RequireHttpsMetadata = true;});// 6. 授权策略services.AddAuthorization(options =>options.AddPolicy("AdminOnly", p => p.RequireClaim("role", "Admin")));// 7. Prometheus HTTP 指标services.AddHttpMetrics();return services;}
}// 限流 Key:Claim client_id 或 IP
public class ClaimClientIdResolveContributor : IClientResolveContributor
{public string Name => "ClientId";public Task<RateLimitClient> ResolveClientAsync(HttpContext context){var clientId = context.User.FindFirst("client_id")?.Value?? context.Connection.RemoteIpAddress?.ToString();return Task.FromResult(new RateLimitClient { Id = clientId });}
}

六、模块化中间件管道扩展 🛣️

public static class GatewayAppExtensions
{public static IApplicationBuilder UseGatewayPipeline(this IApplicationBuilder app){// 1. Serilog 日志 — 最先捕获app.UseSerilogRequestLogging();// 2. 转发头app.UseForwardedHeaders();// 3. 路由app.UseRouting();// 4. CORSapp.UseCors("GatewayCors");// 5. 限流app.UseIpRateLimiting();// 6. 鉴权 / 授权app.UseAuthentication();app.UseAuthorization();// 7. 动态路由级授权app.Use(async (context, next) =>{var endpoint = context.GetEndpoint();var metadata = endpoint?.Metadata.GetMetadata<IDictionary<string, string>>();if (metadata != null && metadata.TryGetValue("AuthorizationPolicy", out var policyName)){var authService = context.RequestServices.GetRequiredService<IAuthorizationService>();var result = await authService.AuthorizeAsync(context.User, policyName);if (!result.Succeeded){context.Response.StatusCode = StatusCodes.Status403Forbidden;await context.Response.WriteAsync("Forbidden");return;}}await next();});// 8. Prometheus HTTP 指标app.UseHttpMetrics();// 9. 端点映射app.UseEndpoints(endpoints =>{endpoints.MapMetrics();            // /metricsendpoints.MapReverseProxy();       // 从 ProxyConfig 加载所有路由endpoints.MapGet("/health", () => Results.Ok("Healthy"));});return app;}
}

6.1 请求管道流程图

GatewayPipeline
Serilog 日志
请求进入
转发头处理
Routing
CORS 验证
限流检查
Authentication
Authorization
动态路由级授权
HttpMetrics
ReverseProxy 转发

七、熔断与重试策略(Polly)🔥

public static IServiceCollection AddPolicyManager(this IReverseProxyBuilder builder)
{builder.Services.AddPolicyRegistry(registry =>{registry.Add("CircuitBreaker", HttpPolicyExtensions.HandleTransientHttpError().CircuitBreakerAsync(3, TimeSpan.FromSeconds(30)));registry.Add("Retry", HttpPolicyExtensions.HandleTransientHttpError().WaitAndRetryAsync(3, retry => TimeSpan.FromSeconds(Math.Pow(2, retry))));});builder.ConfigureHttpClient((ctx, client) =>{client.AddPolicyHandlerFromRegistry("CircuitBreaker");client.AddPolicyHandlerFromRegistry("Retry");});return builder.Services;
}
  • 自动恢复:YARP Active Health Check 自动探测 /health,后台服务恢复后断路器自动闭合。

八、请求限流 🎯

  • IP + ClientID:默认按 IP,ClaimClientIdResolveContributor 支持按 OAuth ClientId 限流。
  • 白名单EndpointWhitelist 中配置 /health
  • 扩展点:可自定义更多 IClientResolveContributorIRateLimitConfiguration

九、与 ABP 认证体系深度集成 🔒

  • 统一鉴权:使用 AddAbpJwtBearer 保持与后端一致的 OIDC/IdentityServer 设置。
  • 路由授权:全局 MapReverseProxy() 后,动态中间件根据 Metadata 中 AuthorizationPolicy 进行精细控制。

十、自定义中间件与扩展点 🛠️

  1. 全链路追踪:在 YARP Transform 中注入 traceparent HTTP 头,配合 OpenTelemetry 收集链路。

  2. 异常统一处理:捕获 BrokenCircuitExceptionRateLimitRejectedException,返回标准化 JSON:

    { "code":"Gateway.CircuitOpen","message":"服务暂不可用,请稍后重试" }
    
  3. 配置中心适配:将 ProxyConfig JSON 存入 Consul/Apollo,实现灰度发布与回滚。


十一、日志与可观测性 📈

  • Serilog + Elasticsearch:生产环境通过 appsettings.Production.json 配置 Sink,结构化存储与查询。
  • Prometheus/metrics 暴露 HTTP 与 YARP EventCounters(需额外配置采集),Grafana 可视化——熔断次数、限流命中率、延迟分布等。

十二、架构全景图 🏗️

请求
RoundRobin
RoundRobin
HealthCheck
CircuitBreaker
Metrics
Logs
Client
API Gateway
ordersvc1
ordersvc2
健康检查
熔断策略
Prometheus
Grafana
Elasticsearch
Kibana

十三、端到端演示与可复现脚本 🚀

13.1 Docker Compose

version: "3.8"
services:gateway:build: ./Gatewayports: ["8080:80"]volumes:- ./Gateway/ProxyConfig:/app/ProxyConfig:ro- ./Gateway/appsettings.json:/app/appsettings.json:ro- ./Gateway/appsettings.Production.json:/app/appsettings.Production.json:roenvironment:- ASPNETCORE_ENVIRONMENT=Productiondepends_on:- ordersvc1- ordersvc2ordersvc1:image: mycompany/ordersvc:latesthealthcheck:test: ["CMD", "curl", "-f", "http://localhost/health"]interval: 10stimeout: 3sordersvc2:image: mycompany/ordersvc:latesthealthcheck:test: ["CMD", "curl", "-f", "http://localhost/health"]interval: 10stimeout: 3sprometheus:image: prom/prometheusvolumes:- ./prometheus.yml:/etc/prometheus/prometheus.ymlelasticsearch:image: docker.elastic.co/elasticsearch/elasticsearch:8.5.1

13.2 k6 压测脚本

import http from 'k6/http';
import { sleep } from 'k6';export let options = {vus: 20,duration: '30s',
};export default function () {http.get('http://localhost:8080/orders/123');sleep(0.1);
}

13.3 Postman Collection

{"info": { "name": "Gateway Tests" },"item": [{"name": "获取订单-正常","request": {"method": "GET","header": [{ "key": "Authorization", "value": "Bearer {{token}}" }],"url": { "raw": "http://localhost:8080/orders/123" }}},{"name": "获取订单-限流触发","request": {"method": "GET","url": { "raw": "http://localhost:8080/orders/123" }}}]
}

http://www.lryc.cn/news/585599.html

相关文章:

  • 七牛云运维面试题及参考答案
  • RabbitMQ 之顺序性保障
  • 单链表,咕咕咕
  • 鸿蒙系统安全机制全解:安全启动 + 沙箱 + 动态权限实战落地指南
  • C语言易错点(二)
  • SEQUENCE在RAC多实例开启CACHE的NEXTVAL数值乱序问题
  • 打破内网壁垒,轻松实现安防视频的云端汇聚与P2P超低延迟播放
  • 【unity编辑器开发与拓展EditorGUILayoyt和GUILayoyt】
  • 数据蓝海里的合规漩涡
  • Windows GNU Radio避坑
  • CUDA程序中的Benchmark耗时测量方法与工具推荐
  • 深度学习笔记30-阿尔茨海默病诊断特征优化版(Pytorch)
  • 和鲸社区深度学习基础训练营2025年关卡4
  • 面试官:你再问TCP三次握手,我就要报警了!
  • uniapp-在windows上IOS真机运行(含开发证书申请流程)
  • 探索飞算 JavaAI 进阶:解锁高效Java开发的新维度
  • Linux进程通信——匿名管道
  • 《打破预设的编码逻辑:Ruby元编程的动态方法艺术》
  • C语言/Keil的register修饰符
  • ​老电影画质为何会模糊?要如何修复呢?
  • 【数据结构与算法】206.反转链表(LeetCode)
  • 力扣-21.合并两个有序链表
  • 力扣-160.相交链表
  • MongoDB(一)
  • “28项评测23项SOTA——GLM-4.1V-9B-Thinking本地部署教程:10B级视觉语言模型的性能天花板!
  • 【SpringBoot】 整合MyBatis+Postgresql
  • 瀚高数据库提交数据后,是否需要COMMIT(APP)
  • 微信小程序核心知识点速览
  • Android simpleperf生成火焰图
  • 《数据库》MySQL备份回复