找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1890

积分

0

好友

264

主题
发表于 2025-11-28 02:27:06 | 查看: 45| 回复: 0

第一章:API 网关与 Ocelot 概述

1.1 什么是 API 网关?

在现代微服务架构中,系统通常被拆分为多个独立部署、松耦合的服务。每个服务暴露自己的 API 接口供客户端或其他服务调用。然而,随着服务数量的增加,直接让客户端与各个微服务通信会带来一系列问题:

  • 客户端复杂性高:客户端需要知道所有微服务的地址、协议、认证方式等。
  • 安全策略难以统一:每个服务都需要实现自己的身份验证、限流、日志记录等逻辑。
  • 跨域问题:浏览器对跨域请求有限制,若多个服务部署在不同域名下,前端需处理复杂的 CORS 配置。
  • 版本管理困难:服务升级时,如何平滑过渡旧版接口?
  • 性能瓶颈:客户端可能需要发起多次请求才能完成一个业务操作(如聚合数据)。

为了解决这些问题,API 网关(API Gateway)应运而生。

API 网关是系统的统一入口,它位于客户端与后端微服务之间,负责路由请求、协议转换、认证鉴权、限流熔断、日志监控等横切关注点(Cross-cutting Concerns)。客户端只需与网关交互,由网关将请求转发到合适的后端服务。

常见的 API 网关包括:

  • Kong(基于 Nginx + Lua)
  • Spring Cloud Gateway(Java 生态)
  • Envoy(Service Mesh 数据平面)
  • Ocelot(.NET 生态专用)

1.2 为什么选择 Ocelot?

Ocelot是一个专为 .NET 平台设计的开源 API 网关,由 ThreeMammals 团队开发,完全基于 ASP.NET Core 构建,具有以下优势:

✅ 轻量级 & 易集成

  • 仅需添加 NuGet 包即可集成到现有 .NET Core 项目。
  • 配置简单,主要通过 JSON 文件定义路由规则。

✅ 功能丰富

支持:

  • 请求路由(Routing)
  • 负载均衡(Load Balancing)
  • 服务发现(Service Discovery,支持 Consul、Eureka)
  • 认证与授权(JWT、IdentityServer 集成)
  • 限流(Rate Limiting)
  • 缓存(Response Caching)
  • 请求/响应转换(Header、Query、Body 修改)
  • 熔断器(Circuit Breaker,集成 Polly)
  • 日志与追踪(Logging & Tracing)

✅ 社区活跃 & 文档完善

  • 持续更新,兼容 .NET 6/7/8
  • 中文社区资料丰富

✅ 与 .NET 生态无缝融合

  • 可与 IdentityServer4/.NET Identity 集成实现统一认证
  • 支持依赖注入、中间件、配置系统等 ASP.NET Core 核心特性

1.3 Ocelot 的核心概念

在深入实战前,需理解 Ocelot 的几个关键组件:

1. ReRoutes(路由)

这是 Ocelot 最核心的配置项。每个ReRoute定义了一条从客户端请求到后端服务的映射规则。

示例:

{  
  "DownstreamPathTemplate": "/api/products/{id}",  
  "DownstreamScheme": "http",  
  "DownstreamHostAndPorts": [    
    {      
      "Host": "product-service",      
      "Port": 8001    
    }  
  ],  
  "UpstreamPathTemplate": "/products/{id}",  
  "UpstreamHttpMethod": [ "Get" ]
}
  • Upstream:客户端请求的路径和方法(网关入口)
  • Downstream:实际转发到的后端服务地址(目标服务)

2. Aggregates(聚合)

将多个下游服务的响应合并为一个响应返回给客户端,减少前端请求数。

3. GlobalConfiguration(全局配置)

定义服务发现、负载均衡、证书、QoS(服务质量)等全局行为。

4. Middleware Pipeline(中间件管道)

Ocelot 内部使用 ASP.NET Core 中间件构建请求处理管道,开发者可自定义中间件扩展功能。

1.4 本系列目标与结构

本实战系列将带你从零搭建一个基于 Ocelot 的完整微服务网关系统,涵盖:

  • 环境搭建与基础路由
  • 负载均衡与服务发现(Consul 集成)
  • JWT 认证与权限控制
  • 限流与熔断机制
  • 请求聚合与响应缓存
  • 日志、监控与 OpenTelemetry 集成
  • Docker 容器化部署
  • 性能优化与生产实践

💡注意:本系列假设你已掌握 .NET Core Web API 基础知识,了解微服务基本概念。

1.5 准备工作

开发环境要求:

  • .NET SDK 8.0(推荐)
  • Visual Studio 2022 / VS Code / Rider
  • Postman 或 curl(用于测试)
  • Docker(可选,用于后续容器化)

创建项目结构

我们将创建以下项目:

MicroservicesSolution/
├── ApiGateway/               ← Ocelot 网关项目
├── ProductService/           ← 示例微服务 1
├── OrderService/             ← 示例微服务 2
└── SharedLibrary/            ← 共享模型(可选)

1.6 创建第一个 Ocelot 网关项目

步骤 1:创建空 ASP.NET Core Web API 项目

dotnet new webapi -n ApiGateway
cd ApiGateway

步骤 2:安装 Ocelot NuGet 包

步骤 3:添加 ocelot.json 配置文件

在项目根目录创建ocelot.json,内容如下:

{  
  "Routes": [    
    {      
      "DownstreamPathTemplate": "/weatherforecast",      
      "DownstreamScheme": "http",      
      "DownstreamHostAndPorts": [        
        {          
          "Host": "localhost",          
          "Port": 5001        
        }      
      ],      
      "UpstreamPathTemplate": "/forecast",      
      "UpstreamHttpMethod": [ "Get" ]    
    }  
  ],  
  "GlobalConfiguration": {    
    "BaseUrl": "http://localhost:5000"  
  }
}

⚠️ 注意:我们将用默认的 WeatherForecastController 作为测试服务。

步骤 4:修改 Program.cs

var builder = WebApplication.CreateBuilder(args);
// 添加 Ocelot 配置
builder.Configuration.AddJsonFile("ocelot.json");
builder.Services.AddOcelot(builder.Configuration);
var app = builder.Build();
await app.UseOcelot(); // 启用 Ocelot 中间件
app.Run();

步骤 5:启动一个测试服务

创建另一个 Web API 项目作为下游服务:

dotnet new webapi -n WeatherService
cd WeatherService
dotnet run --urls "http://localhost:5001"

步骤 6:启动网关并测试

回到ApiGateway目录:

dotnet run --urls "http://localhost:5000"

然后访问:

GET http://localhost:5000/forecast

你应该看到来自WeatherService的响应!

恭喜!你已成功搭建第一个 Ocelot 网关!

1.7 小结

本章我们:

  • 理解了 API 网关的作用与价值
  • 认识了 Ocelot 的优势与核心功能
  • 搭建了最简单的 Ocelot 路由示例

第二章:Ocelot 路由配置详解与高级匹配规则

在第一章中,我们成功搭建了一个最简单的 Ocelot 网关,并实现了基本的请求转发。然而,在真实项目中,路由需求往往更加复杂:需要支持动态参数、多种 HTTP 方法、路径通配、请求头匹配、甚至基于查询字符串或主机名的路由。本章将深入剖析 Ocelot 的路由(ReRoutes)配置体系,带你掌握所有核心匹配规则与高级用法。

📌提示:从 Ocelot v17 开始,官方推荐使用Routes替代旧版ReRoutes字段(语义更清晰),但两者功能一致。本文统一使用Routes

2.1 路由配置结构解析

一个完整的路由对象包含以下关键字段:

{  
  "DownstreamPathTemplate": "/api/v1/users/{id}",  
  "DownstreamScheme": "https",  
  "DownstreamHostAndPorts": [    
    { "Host": "user-service", "Port": 8080 }  
  ],  
  "UpstreamPathTemplate": "/users/{id}",  
  "UpstreamHttpMethod": [ "Get", "Put" ],  
  "Key": "user-detail-route",  
  "Priority": 1,  
  "RouteClaimsRequirement": { ... },  
  "AuthenticationOptions": { ... },  
  "RateLimitOptions": { ... },  
  "QoSOptions": { ... },  
  "FileCacheOptions": { ... },  
  "AddHeadersToRequest": { ... },  
  "AddClaimsToRequest": { ... },  
  "AddQueriesToRequest": { ... },  
  "TransformHeaders": { ... }
}

我们将逐项详解。

2.2 Upstream 与 Downstream 模板匹配

2.2.1 路径模板(Path Template)

Ocelot 使用占位符 {}实现路径变量传递。

✅ 示例 1:简单参数传递

{  
  "UpstreamPathTemplate": "/products/{id}",  
  "DownstreamPathTemplate": "/api/products/{id}"
}
  • 请求 /products/123 → 转发到 /api/products/123

✅ 示例 2:多参数

{  
  "UpstreamPathTemplate": "/orders/{orderId}/items/{itemId}",  
  "DownstreamPathTemplate": "/v2/orders/{orderId}/lineitems/{itemId}"
}

⚠️ 注意:占位符名称必须一致,否则无法正确映射!

2.2.2 通配符(Catch-all)支持

Ocelot 支持/{everything}形式的通配符,用于捕获任意子路径。

✅ 示例:代理整个子系统

{  
  "UpstreamPathTemplate": "/admin/{everything}",  
  "DownstreamPathTemplate": "/{everything}"
}
  • /admin/dashboard → /dashboard
  • /admin/api/users → /api/users

🔒 安全提示:通配符需谨慎使用,避免暴露内部接口。

2.3 HTTP 方法匹配(UpstreamHttpMethod)

默认情况下,若未指定UpstreamHttpMethod,Ocelot 会匹配所有方法。但通常建议显式声明。

✅ 示例:

"UpstreamHttpMethod": [ "Get" ]
"UpstreamHttpMethod": [ "Post", "Put", "Delete" ]

💡 技巧:可配合多个路由实现同一路径不同方法的不同转发目标。

2.4 路由优先级(Priority)

当多个路由规则可能匹配同一个请求时,Ocelot 默认按配置顺序匹配第一个。但可通过Priority字段显式控制。

  • 数值越大,优先级越高(类似 CSS 的 z-index)
  • 默认优先级为 0

✅ 示例:

[  
  {    
    "UpstreamPathTemplate": "/api/{everything}",    
    "Priority": 1,    
    "DownstreamPathTemplate": "/fallback/{everything}"  
  },  
  {    
    "UpstreamPathTemplate": "/api/users",    
    "Priority": 2,  // 优先匹配此路由    
    "DownstreamPathTemplate": "/user-service/users"  
  }
]
  • 请求 /api/users → 匹配第二条(优先级 2 > 1)
  • 请求 /api/orders → 匹配第一条(无更高优先级匹配)

✅ 最佳实践:将具体路径放在高优先级,通配或通用规则放低优先级。

2.5 基于 Host 的路由(Host 匹配)

Ocelot 支持根据请求的Host 头进行路由,适用于多租户或多域名场景。

配置方式:在UpstreamHost字段指定。

✅ 示例:

{  
  "UpstreamHost": "shop.example.com",  
  "UpstreamPathTemplate": "/products",  
  "DownstreamPathTemplate": "/catalog/products"
}

⚠️ 注意:UpstreamHost必须与客户端请求的Host头完全一致(区分大小写)。

2.6 查询字符串与请求头匹配(高级条件)

Ocelot 本身不直接支持基于 Query String 或 Header 的路由匹配。但可通过以下方式间接实现:

方案 1:自定义中间件预处理

UseOcelot()之前插入中间件,修改HttpContext.Request.Path,使其符合某个UpstreamPathTemplate

方案 2:使用聚合服务 + 条件逻辑

将请求先转发到一个“路由决策服务”,由该服务根据 Header/Query 决定下一步调用哪个真实服务。

🔜 后续章节将演示如何通过自定义中间件扩展路由逻辑。

2.7 路径重写与请求转换

除了转发,Ocelot 还支持在转发前修改请求内容

2.7.1 添加/覆盖请求头

"AddHeadersToRequest": {  
  "X-Custom-Source": "API-Gateway",  
  "Authorization": "Bearer {Token}" // 可引用 Claims
}

2.7.2 添加查询参数

"AddQueriesToRequest": {  
  "source": "gateway",  
  "version": "v1"
}

2.7.3 注入 Claims 到请求头(配合认证)

"AddClaimsToRequest": {  
  "UserId": "sub",  
  "Role": "role"
}
  • 将 JWT 中的 sub 声明值注入到 UserId 请求头

2.8 实战:构建多版本 API 路由

假设我们有两个用户服务:

目标:通过路径前缀区分版本。

步骤 1:创建 ocelot.json

{  
  "Routes": [    
    {      
      "UpstreamPathTemplate": "/v1/users/{id}",      
      "DownstreamPathTemplate": "/users/{id}",      
      "DownstreamScheme": "http",      
      "DownstreamHostAndPorts": [        
        { "Host": "localhost", "Port": 6001 }      
      ],      
      "UpstreamHttpMethod": [ "Get" ],      
      "Priority": 10    
    },    
    {      
      "UpstreamPathTemplate": "/v2/users/{id}",      
      "DownstreamPathTemplate": "/api/users/{id}",      
      "DownstreamScheme": "http",      
      "DownstreamHostAndPorts": [        
        { "Host": "localhost", "Port": 6002 }      
      ],      
      "UpstreamHttpMethod": [ "Get" ],      
      "Priority": 10    
    },    
    {      
      "UpstreamPathTemplate": "/users/{id}",      
      "DownstreamPathTemplate": "/users/{id}",      
      "DownstreamScheme": "http",      
      "DownstreamHostAndPorts": [        
        { "Host": "localhost", "Port": 6001 }      
      ],      
      "UpstreamHttpMethod": [ "Get" ],      
      "Priority": 1  // 默认回退到 v1    
    }  
  ],  
  "GlobalConfiguration": {    
    "BaseUrl": "http://localhost:5000"  
  }
}

步骤 2:启动两个用户服务(模拟)

# 终端1
dotnet run --project UserService.V1 --urls "http://localhost:6001"
# 终端2
dotnet run --project UserService.V2 --urls "http://localhost:6002"

步骤 3:测试

curl http://localhost:5000/v1/users/1   # → 6001
curl http://localhost:5000/v2/users/1   # → 6002
curl http://localhost:5000/users/1      # → 6001(默认)

✅ 成功实现多版本路由!

2.9 路由配置热更新(开发友好)

Ocelot 支持在运行时重新加载ocelot.json,无需重启网关。

启用方式(Program.cs):

builder.Configuration  
    .AddJsonFile("ocelot.json", optional: false, reloadOnChange: true);

🔔 修改ocelot.json后,Ocelot 会自动应用新配置(约 1 秒延迟)。

2.10 路由配置验证与调试

日志输出

appsettings.json中启用 Ocelot 日志:

{  
  "Logging": {    
    "LogLevel": {      
      "Default": "Information",      
      "Ocelot": "Debug"    
    }  
  }
}

你将看到类似日志:

[Debug] Matched route: user-detail-route
[Debug] Downstream url: http://localhost:6001/users/123

使用 Admin API(可选)

Ocelot 提供实验性 Admin API(需额外配置),可用于动态管理路由,但生产环境慎用。

2.11 小结

本章我们深入学习了 Ocelot 的路由机制,掌握了:

  • 路径模板与参数传递
  • 通配符与多方法匹配
  • 路由优先级控制
  • Host 匹配与请求转换
  • 多版本 API 实战案例
  • 配置热更新与调试技巧

这些知识是构建灵活、健壮 API 网关的基础。

第三章:Ocelot 集成 Consul 实现服务发现与动态负载均衡

在微服务架构中,服务实例的数量和地址是动态变化的——可能因扩缩容、故障重启、容器调度等原因频繁变动。如果在 Ocelot 配置中硬编码每个服务的HostPort(如"localhost:5001"),将导致网关配置僵化、难以维护,甚至服务不可用。

为解决这一问题,我们需要引入服务注册与发现(Service Registration and Discovery)机制。本章将使用业界广泛采用的Consul作为服务注册中心,与 Ocelot 深度集成,实现:

  • 微服务自动注册到 Consul
  • Ocelot 动态从 Consul 获取服务实例列表
  • 自动负载均衡(轮询、最少连接等)
  • 故障实例自动剔除

✅ 本章目标:构建一个具备服务发现能力的弹性 API 网关。

3.1 什么是 Consul?

Consul是 HashiCorp 开发的一款开源工具,提供以下核心功能:

  • 服务注册与发现:服务启动时注册自身,客户端通过名称发现实例。
  • 健康检查:自动检测服务是否存活,剔除不健康节点。
  • KV 存储:可用于配置共享。
  • 多数据中心支持:适合复杂部署环境。

官网:https://www.consul.io/

图片

3.2 整体架构设计

Client   
│   
▼
[Ocelot Gateway] ←───┐   
│                  │ 查询服务列表   
▼                  ▼
[Consul Server] ← [UserService Instance 1]  
                   [UserService Instance 2]  
                   [OrderService Instance 1]

流程:

  1. 微服务启动时,向 Consul 注册自己(服务名 + 地址 + 健康检查端点)
  2. Ocelot 配置路由时,不再写死 IP/Port,而是使用 服务名(如 "ServiceName": "user-service")
  3. Ocelot 定期从 Consul 拉取该服务的所有健康实例
  4. 请求到来时,Ocelot 从实例列表中选择一个进行转发(负载均衡)

3.3 环境准备:启动 Consul

方式 1:Docker(推荐)

docker run -d \
  --name=consul \
  -p 8500:8500 \
  -p 8600:8600/udp \
  consul agent -server -bootstrap-expect=1 -ui -client=0.0.0.0 -bind=0.0.0.0 -data-dir=/consul/data

访问 Web UI:http://localhost:8500

方式 2:本地安装(Windows/macOS/Linux)

从https://www.consul.io/downloads下载并解压,添加到 PATH。

启动开发模式:

consul agent -dev -ui -client=0.0.0.0

💡-dev模式仅用于开发,生产环境需集群部署。

3.4 微服务:集成 Consul 客户端并自动注册

我们将以UserService为例,演示如何注册到 Consul。

步骤 1:创建 UserService 项目

dotnet new webapi -n UserService
cd UserService

步骤 2:安装 Consul 客户端包

dotnet add package Consul

步骤 3:添加服务注册逻辑

创建ConsulServiceRegistration.cs

using Consul;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

public static class ConsulServiceRegistration
{
    public static IHost RegisterWithConsul(this IHost host, string serviceName, int servicePort)
    {
        var lifetime = host.Services.GetRequiredService<IHostApplicationLifetime>();
        var consulClient = new ConsulClient(config =>
        {
            config.Address = new Uri("http://localhost:8500"); // Consul 地址
        });
        var httpConfig = host.Services.GetRequiredService<IWebHostEnvironment>();
        var address = "localhost"; // 生产环境应使用内网IP或容器网络名
        var registration = new AgentServiceRegistration()
        {
            ID = $"{serviceName}-{address}:{servicePort}",
            Name = serviceName,
            Address = address,
            Port = servicePort,
            Check = new AgentServiceCheck()
            {
                HTTP = $"http://{address}:{servicePort}/health",
                Interval = TimeSpan.FromSeconds(10),
                Timeout = TimeSpan.FromSeconds(5),
                DeregisterCriticalServiceAfter = TimeSpan.FromMinutes(1)
            }
        };
        // 服务启动时注册
        lifetime.ApplicationStarted.Register(async () =>
        {
            await consulClient.Agent.ServiceDeregister(registration.ID);
            await consulClient.Agent.ServiceRegister(registration);
        });
        // 服务停止时注销
        lifetime.ApplicationStopping.Register(async () =>
        {
            await consulClient.Agent.ServiceDeregister(registration.ID);
        });
        return host;
    }
}

步骤 4:添加健康检查端点

Program.cs中添加:

app.MapGet("/health", () => Results.Ok("Healthy"));

步骤 5:在 Program.cs 中启用注册

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}
app.MapGet("/users/{id}", (string id) => 
    new { Id = id, Name = "John Doe", Service = "UserService v1" });
app.MapGet("/health", () => Results.Ok("Healthy"));
var port = 6001; // 可通过配置读取
app.Urls.Add($"http://localhost:{port}");
// 注册到 Consul
app.Services.GetRequiredService<IHost>().RegisterWithConsul("user-service", port);
app.Run();

🔁 你可以复制此项目,修改端口和服务名为6002user-service,启动多个实例模拟集群。

3.5 Ocelot 网关:配置服务发现

步骤 1:安装 Ocelot.Provider.Consul

ApiGateway项目中:

dotnet add package Ocelot.Provider.Consul

步骤 2:修改 ocelot.json

{  
  "Routes": [    
    {      
      "DownstreamPathTemplate": "/users/{id}",      
      "DownstreamScheme": "http",      
      "ServiceName": "user-service",   // ← 关键:使用服务名替代 HostAndPorts      
      "UpstreamPathTemplate": "/api/users/{id}",      
      "UpstreamHttpMethod": [ "Get" ]    
    }  
  ],  
  "GlobalConfiguration": {    
    "ServiceDiscoveryProvider": {      
      "Host": "localhost",      
      "Port": 8500,      
      "Type": "Consul"    
    },    
    "LoadBalancerOptions": {      
      "Type": "RoundRobin"  // 轮询负载均衡    
    },    
    "BaseUrl": "http://localhost:5000"  
  }
}

⚠️ 注意:一旦使用ServiceName,就不要再写DownstreamHostAndPorts

步骤 3:在 Program.cs 中注册 Consul 服务发现

var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddJsonFile("ocelot.json");
builder.Services.AddOcelot(builder.Configuration)  
                .AddConsul(); // ← 启用 Consul 集成
var app = builder.Build();
await app.UseOcelot();
app.Run();

3.6 启动并测试

启动顺序:

  1. 启动 Consul(Docker 或本地)
  2. 启动两个 UserService 实例(端口 6001 和 6002)
  3. 启动 ApiGateway(端口 5000)

测试负载均衡:

连续请求多次:

curl http://localhost:5000/api/users/1

观察响应中的Service字段:

  • 第一次:"Service": "UserService v1"(6001)
  • 第二次:"Service": "UserService v1"(6002)
  • 第三次:6001 ……

✅ 成功实现轮询负载均衡!

模拟故障:

关闭 6001 实例,等待 10 秒(健康检查间隔),再次请求:

  • 所有请求自动路由到 6002
  • Consul UI 中 6001 实例显示为“critical”并被剔除

3.7 负载均衡策略

Ocelot 支持多种负载均衡算法:

类型 说明
RoundRobin 轮询(默认)
LeastConnection 选择当前连接数最少的实例
NoLoadBalancer 禁用负载均衡(仅用于单实例)

配置方式(全局或每路由):

"LoadBalancerOptions": {  
  "Type": "LeastConnection"
}

3.8 服务发现高级配置

自定义 Consul 客户端

可通过代码注入自定义ConsulClient,例如添加 ACL Token:

builder.Services.AddOcelot(builder.Configuration)  
                .AddConsul()  
                .ConfigureConsulClient((config, serviceProvider) =>  
                {  
                    config.Token = "your-acl-token";  
                });

服务版本与标签过滤

Consul 支持为服务打标签(Tags),Ocelot 可通过UseServiceDiscovery+ 自定义IServiceDiscoveryFinder实现标签过滤(需扩展)。

3.9 小结

本章我们完成了:

  • Consul 的本地部署
  • 微服务自动注册与健康检查
  • Ocelot 与 Consul 集成
  • 动态服务发现与负载均衡
  • 故障自动隔离验证

现在,我们的网关已具备弹性伸缩高可用能力,为后续认证、限流等模块打下坚实基础。

第四章:Ocelot 集成 JWT 实现统一认证与授权

在微服务架构中,每个服务都可能需要验证用户身份和权限。如果每个服务都重复实现认证逻辑,不仅代码冗余,还容易出现安全漏洞或策略不一致。API 网关天然适合作为统一认证入口——客户端只需携带 Token 访问网关,由网关完成验证,并将用户身份信息(如用户ID、角色)透传给下游服务。

本章将使用JWT(JSON Web Token)作为认证机制,在 Ocelot 网关层集成ASP.NET Core 的 JWT Bearer 认证,实现:

  • 客户端请求携带 JWT Token
  • Ocelot 验证 Token 有效性(签名、过期时间等)
  • 放行合法请求,拒绝非法请求(401/403)
  • 将用户声明(Claims)注入请求头,供下游服务使用

✅ 技术栈:JWT + IdentityModel + Ocelot 内置认证支持

4.1 JWT 认证原理简述

JWT 是一种开放标准(RFC 7519),用于在各方之间安全地传输信息。一个典型的 JWT 由三部分组成:

Header.Payload.Signature
  • Header:算法和令牌类型(如 {"alg": "HS256", "typ": "JWT"})
  • Payload:用户声明(Claims),如 sub(用户ID)、role、exp(过期时间)
  • Signature:对前两部分的签名,确保令牌未被篡改

服务端使用密钥(Secret)公私钥对验证签名。

🔐 安全提示:JWT 本身不加密(除非使用 JWE),仅防篡改。敏感信息不应放入 Payload。

4.2 整体认证流程

Client → [Login] → AuthServer → 返回 JWT   
│   
▼ (携带 Authorization: Bearer <token>)
[Ocelot Gateway] → 验证 JWT   
│   
├── 无效? → 返回 401 Unauthorized   
└── 有效? → 转发请求 + 注入 Claims 到 Header → [Downstream Service]

下游服务无需再验证 Token,只需信任网关传来的身份信息(可通过内部网络隔离保证安全)。

4.3 准备工作:生成测试 JWT

为简化,我们先手动创建一个 JWT(生产环境应由独立的认证服务如 IdentityServer 或自研 Auth API 生成)。

使用 jwt.io 生成(临时测试)

访问https://jwt.io/,填写:

HEADER

{  
  "alg": "HS256",  
  "typ": "JWT"
}

PAYLOAD

{  
  "sub": "user123",  
  "name": "John Doe",  
  "role": "admin",  
  "exp": 1735689600  // 2025-01-01 00:00:00 UTC
}

VERIFY SIGNATURE

your-super-secret-key

生成的 Token 示例:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyMTIzIiwibmFtZSI6IkpvaG4gRG9lIiwicm9sZSI6ImFkbWluIiwiZXhwIjoxNzM1Njg5NjAwfQ.abc123...

⚠️ 请务必使用强密钥(至少32位随机字符串),此处仅为演示。

4.4 Ocelot 网关集成 JWT 认证

步骤 1:安装必要 NuGet 包

ApiGateway项目中:

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

注意:Ocelot 本身不处理认证,而是依赖 ASP.NET Core 的认证中间件。

步骤 2:配置 JWT 认证(Program.cs)

var builder = WebApplication.CreateBuilder(args);
// 加载 Ocelot 配置
builder.Configuration.AddJsonFile("ocelot.json");
// 添加 JWT Bearer 认证
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)  
    .AddJwtBearer(options =>  
    {  
        options.TokenValidationParameters = new TokenValidationParameters  
        {  
            ValidateIssuerSigningKey = true,  
            IssuerSigningKey = new SymmetricSecurityKey(  
                Encoding.UTF8.GetBytes("your-super-secret-key") // ← 与生成 Token 的密钥一致  
            ),  
            ValidateIssuer = false,      // 可选:验证 issuer  
            ValidateAudience = false,    // 可选:验证 audience  
            ValidateLifetime = true,     // 必须:验证过期时间  
            ClockSkew = TimeSpan.Zero    // 不允许时间偏差  
        };  
    });
// 添加 Ocelot
builder.Services.AddOcelot(builder.Configuration);
var app = builder.Build();
// 启用认证 & Ocelot
app.UseAuthentication();  // ← 必须在 UseOcelot 之前
await app.UseOcelot();
app.Run();

🔑 关键点:

  • UseAuthentication() 必须在 UseOcelot() 之前调用
  • 密钥必须与签发 Token 时一致

步骤 3:在路由中启用认证

修改ocelot.json,为需要保护的路由添加AuthenticationOptions

{  
  "Routes": [    
    {      
      "DownstreamPathTemplate": "/users/{id}",      
      "DownstreamScheme": "http",      
      "ServiceName": "user-service",      
      "UpstreamPathTemplate": "/api/users/{id}",      
      "UpstreamHttpMethod": [ "Get" ],      
      "AuthenticationOptions": {        
        "AuthenticationProviderKey": "Bearer",  // 对应 JwtBearerDefaults.AuthenticationScheme        
        "AllowedScopes": []  // 若使用 OAuth2 scope,可在此限制      
      }    
    }  
  ],  
  "GlobalConfiguration": {    
    "ServiceDiscoveryProvider": {      
      "Host": "localhost",      
      "Port": 8500,      
      "Type": "Consul"    
    },    
    "BaseUrl": "http://localhost:5000"  
  }
}

💡AuthenticationProviderKey必须与AddJwtBearer注册的方案名一致(默认为"Bearer")。

4.5 测试认证效果

测试 1:无 Token 访问(应返回 401)

curl -i http://localhost:5000/api/users/1

响应:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer

测试 2:携带无效 Token(应返回 401)

curl -i -H "Authorization: Bearer invalid-token" http://localhost:5000/api/users/1

测试 3:携带有效 Token(应成功转发)

curl -i -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxx" \  
     http://localhost:5000/api/users/1

✅ 成功返回用户数据!

4.6 将用户身份传递给下游服务

认证通过后,我们通常希望下游服务知道“谁在调用”。Ocelot 支持将Claims 注入请求头

修改 ocelot.json:

{  
  "Routes": [    
    {      
      "DownstreamPathTemplate": "/users/{id}",      
      "DownstreamScheme": "http",      
      "ServiceName": "user-service",      
      "UpstreamPathTemplate": "/api/users/{id}",      
      "UpstreamHttpMethod": [ "Get" ],      
      "AuthenticationOptions": {        
        "AuthenticationProviderKey": "Bearer"      
      },      
      "AddClaimsToRequest": {        
        "X-User-Id": "sub",        
        "X-User-Role": "role",        
        "X-User-Name": "name"      
      }    
    }  
  ]
}

下游服务(UserService)读取 Header:

UserService的控制器中:

app.MapGet("/users/{id}", (string id, HttpRequest request) =>
{
    var userId = request.Headers["X-User-Id"].FirstOrDefault();
    var role = request.Headers["X-User-Role"].FirstOrDefault();
    return new {  
        RequestedUserId = id,  
        CurrentUserId = userId,  
        Role = role,  
        Service = "UserService"  
    };
});

测试:

curl -H "Authorization: Bearer <valid-jwt>" http://localhost:5000/api/users/999

响应:

{  
  "requestedUserId": "999",  
  "currentUserId": "user123",  
  "role": "admin",  
  "service": "UserService"
}

✅ 身份信息成功透传!

4.7 基于角色的授权(可选)

Ocelot 本身不直接支持基于角色的授权(如[Authorize(Roles = "admin")]),但可通过以下方式实现:

方案 1:在下游服务做授权

  • 网关只负责认证
  • 下游服务根据 X-User-Role 头判断是否有权限

方案 2:使用 RouteClaimsRequirement(简单场景)

在路由中配置:

"RouteClaimsRequirement": {  
  "role": "admin"
}

只有当 JWT 中包含"role": "admin"时才放行。

⚠️ 局限性:仅支持精确匹配,不支持多角色、策略授权等复杂场景。

4.8 生产环境建议

  1. 使用 HTTPS:防止 Token 被窃听
  2. 密钥管理:不要硬编码密钥,使用 Azure Key Vault / AWS Secrets Manager / 环境变量
  3. Token 过期时间:设置合理(如 15~60 分钟),配合 Refresh Token 机制
  4. 认证服务独立化:使用 IdentityServer、Auth0 或自研 OAuth2 Server
  5. 日志审计:记录认证失败尝试,防范暴力破解

4.9 小结

本章我们实现了:

  • 在 Ocelot 网关层集成 JWT Bearer 认证
  • 保护特定路由,拒绝未认证请求
  • 将用户 Claims 注入请求头,透传身份信息
  • 下游服务无感知地获取调用者身份

现在,我们的网关已具备统一安全边界,为后续的限流、缓存、监控等功能奠定基础。

第五章:Ocelot 实现 API 限流与熔断保护

在高并发或恶意攻击场景下,后端微服务可能因请求过载而崩溃。为保障系统稳定性,API 网关需具备流量控制能力。本章将深入讲解 Ocelot 提供的两大核心防护机制:

  1. 限流(Rate Limiting):限制单位时间内客户端可发起的请求数,防止滥用。
  2. 熔断(Circuit Breaker):当下游服务持续失败时,自动“熔断”请求,避免雪崩,并支持快速失败与恢复。

我们将通过实战配置,构建一个具备弹性容错能力的安全网关。

5.1 限流(Rate Limiting)详解

5.1.1 限流的作用

  • 防止 DDoS 或爬虫攻击
  • 保障核心服务资源不被耗尽
  • 实现 API 计费策略(如免费用户 100 次/分钟,付费用户 1000 次/分钟)

5.1.2 Ocelot 限流原理

Ocelot 基于内存(默认)或分布式缓存(如 Redis)记录每个客户端的请求次数。当超过阈值时,返回429 Too Many Requests

⚠️ 默认使用内存存储,仅适用于单实例网关。多实例部署必须集成 Redis!

5.2 实战:配置基础限流

步骤 1:在路由中启用限流

修改ocelot.json

{  
  "Routes": [    
    {      
      "DownstreamPathTemplate": "/users/{id}",      
      "DownstreamScheme": "http",      
      "ServiceName": "user-service",      
      "UpstreamPathTemplate": "/api/users/{id}",      
      "UpstreamHttpMethod": [ "Get" ],      
      "RateLimitOptions": {        
        "ClientWhitelist": [],     // 白名单客户端ID(可选)        
        "EnableRateLimiting": true,        
        "Period": "1m",            // 时间窗口:1分钟        
        "PeriodTimespan": 60,      // 重置时间(秒),通常等于 Period        
        "Limit": 5                 // 最大请求数      
      }    
    }  
  ],  
  "GlobalConfiguration": {    
    "BaseUrl": "http://localhost:5000",    
    "ServiceDiscoveryProvider": {      
      "Host": "localhost",      
      "Port": 8500,      
      "Type": "Consul"    
    }  
  }
}

关键参数说明:

字段 说明
EnableRateLimiting 是否启用限流
Period 时间窗口(支持s秒、m分、h小时,如"30s"
Limit Period内允许的最大请求数
ClientWhitelist 不受限制的客户端 ID 列表(需配合客户端识别)

步骤 2:识别客户端(默认基于 IP)

Ocelot 默认使用HttpContext.Connection.RemoteIpAddress作为客户端标识。

🔐 安全提示:若网关前有反向代理(如 Nginx),需确保X-Forwarded-For头被正确处理,否则所有请求将被视为同一 IP。

步骤 3:测试限流效果

连续发送 6 次请求:

for i in {1..6}; do  
  curl -i -H "Authorization: Bearer <valid-jwt>" http://localhost:5000/api/users/1
done

前 5 次:200 OK
第 6 次:

HTTP/1.1 429 Too Many Requests
Retry-After: 60
Content-Type: application/json

响应体:

{ "message": "Too many requests, retry after 60 seconds." }

✅ 限流生效!

5.3 高级限流:自定义客户端 ID

有时需按用户、租户或 API Key 限流。可通过中间件注入X-Rate-Limit-Client-Id头。

示例:按用户 ID 限流

Program.cs中添加中间件(必须在 UseAuthentication 之后,UseOcelot 之前):

app.Use(async (context, next) =>
{
    if (context.User.Identity?.IsAuthenticated == true)
    {
        var userId = context.User.FindFirst("sub")?.Value;
        if (!string.IsNullOrEmpty(userId))
        {
            context.Request.Headers.Append("X-Rate-Limit-Client-Id", userId);
        }
    }
    await next();
});

现在,限流将基于用户 ID 而非 IP。

💡 结合 JWT 认证,实现“每个用户每分钟最多 5 次请求”。

5.4 多实例网关:集成 Redis 实现分布式限流

当部署多个 Ocelot 实例时,内存限流失效。需使用Redis统一计数。

步骤 1:安装 Redis 支持包

dotnet add package Ocelot.Provider.Redis

步骤 2:启动 Redis(Docker)

docker run -d --name redis -p 6379:6379 redis

步骤 3:注册 Redis 限流提供者

Program.cs中:

builder.Services.AddOcelot(builder.Configuration)  
                .AddConsul()  
                .AddRedisRateLimiting(); // ← 启用 Redis 限流

步骤 4:配置 Redis 连接(appsettings.json)

{  
  "Redis": {    
    "QuotaExpiryInSeconds": 60,    
    "RateLimitCounterPrefix": "ocelot:ratelimit:"  
  },  
  "ConnectionStrings": {    
    "Redis": "localhost:6379"  
  }
}

✅ 现在,所有 Ocelot 实例共享同一限流计数器!

5.5 熔断器(Circuit Breaker)机制

5.5.1 什么是熔断?

源自电力系统:当电路过载,保险丝熔断以保护设备。
在微服务中:当下游服务持续失败(如超时、5xx 错误),网关自动停止转发请求一段时间,直接返回错误,避免连锁故障。

5.5.2 Ocelot 熔断原理

基于Polly库实现。配置阈值,当失败率达到上限,触发熔断。

5.6 配置熔断规则

在路由中添加QoSOptions(Quality of Service):

{  
  "Routes": [    
    {      
      "DownstreamPathTemplate": "/orders",      
      "DownstreamScheme": "http",      
      "ServiceName": "order-service",      
      "UpstreamPathTemplate": "/api/orders",      
      "UpstreamHttpMethod": [ "Get" ],      
      "QoSOptions": {        
        "ExceptionsAllowedBeforeBreaking": 3,  // 允许多少次异常后熔断        
        "DurationOfBreak": 10,                 // 熔断持续时间(秒)        
        "TimeoutValue": 5000                   // 请求超时(毫秒)      
      }    
    }  
  ]
}

参数说明:

字段 说明
ExceptionsAllowedBeforeBreaking 连续失败次数阈值(如 3 次 500 错误)
DurationOfBreak 熔断后暂停转发的时间(秒)
TimeoutValue 单个请求最大等待时间(毫秒),超时视为失败

测试熔断:

  1. 启动一个会返回 500 的 order-service
  2. 连续请求 3 次 /api/orders
  3. 第 4 次请求将直接返回 503 Service Unavailable(无需等待)
  4. 等待 10 秒后,请求恢复正常尝试

📊 熔断期间,Ocelot 会定期尝试“半开”状态,探测服务是否恢复。

5.7 限流与熔断结合的最佳实践

场景 推荐策略
公开 API 严格限流(防爬虫) + 熔断(防雪崩)
内部服务调用 较宽松限流 + 强熔断
支付等关键接口 高优先级 + 低熔断阈值

5.8 小结

本章我们实现了:

  • 基于 IP 或用户 ID 的 API 限流
  • Redis 分布式限流支持多实例网关
  • 基于 Polly 的熔断机制,防止级联故障
  • 限流与熔断的生产级配置建议

现在,我们的网关已具备流量治理故障隔离能力,显著提升系统鲁棒性。

第六章:Ocelot 响应缓存与性能优化实战

在高并发场景下,大量重复请求(如商品详情、用户资料)会反复穿透网关、调用后端服务,造成不必要的资源消耗。响应缓存(Response Caching)是提升系统吞吐量、降低延迟的有效手段。

Ocelot 内置了基于内存的响应缓存机制,支持按路由配置缓存策略,将符合条件的响应暂存一段时间,后续相同请求直接返回缓存结果,无需转发至下游服务。

本章将带你掌握:

  • Ocelot 缓存的工作原理
  • 配置路由级缓存策略
  • 控制缓存键(Cache Key)生成规则
  • 集成分布式缓存(Redis)
  • 缓存与认证、限流的协同使用

6.1 响应缓存适用场景

适合缓存的接口特征

  • 数据变更不频繁(如商品信息、配置数据)
  • 请求参数相同则响应相同(幂等性)
  • 公开或低敏感数据(避免缓存用户私有信息)

不适合缓存的接口

  • 涉及用户隐私(如 /my/profile)
  • 实时性要求高(如股票价格)
  • 带副作用的操作(POST/PUT/DELETE)

💡 最佳实践:只对 GET 请求启用缓存

6.2 启用基础响应缓存

步骤 1:在路由中配置缓存

修改ocelot.json

{  
  "Routes": [    
    {      
      "DownstreamPathTemplate": "/products/{id}",      
      "DownstreamScheme": "http",      
      "ServiceName": "product-service",      
      "UpstreamPathTemplate": "/api/products/{id}",      
      "UpstreamHttpMethod": [ "Get" ],      
      "FileCacheOptions": {        
        "TtlSeconds": 30  // 缓存有效期:30秒      
      }    
    }  
  ],  
  "GlobalConfiguration": {    
    "BaseUrl": "http://localhost:5000",    
    "ServiceDiscoveryProvider": {      
      "Host": "localhost",      
      "Port": 8500,      
      "Type": "Consul"    
    }  
  }
}

⚠️ 字段名为FileCacheOptions是历史遗留(早期基于文件),实际默认使用内存缓存

步骤 2:确保下游服务支持缓存语义(可选但推荐)

ProductService中设置缓存头:

app.MapGet("/products/{id}", (string id) =>
{
    return Results.Json(new { Id = id, Name = "Laptop", Price = 9999 },   
        statusCode: 200,   
        contentType: "application/json",  
        // 可选:添加 Cache-Control 头  
        new Dictionary<string, IEnumerable<string>>  
        {  
            ["Cache-Control"] = new[] { "public, max-age=30" }  
        });
});

🔔 Ocelot 的FileCacheOptions.TtlSeconds优先级高于响应头。

6.3 缓存键(Cache Key)生成规则

Ocelot 默认使用以下信息生成缓存键:

  • UpstreamPathTemplate(如 /api/products/123)
  • HTTP 方法(GET/POST...)
  • 查询字符串(Query String)
  • 授权头(Authorization)—— 关键!

为什么包含 Authorization?

为防止用户 A 的私有数据被缓存后返回给用户 B。

✅ 示例:

  • 用户 A 请求 /api/profile → 缓存键包含其 Token → 响应缓存
  • 用户 B 请求 /api/profile → Token 不同 → 缓存未命中 → 转发到后端

🛡️ 安全设计:带认证的请求默认不会跨用户共享缓存

如何禁用 Authorization 参与缓存键?(仅用于公开接口)

通过全局配置关闭:

"GlobalConfiguration": {  
  "RequestIdKey": null,  
  "AdministrationPath": null,  
  "CacheStoreOptions": {    
    "Region": "OcelotCache",    
    "UseDistributedCache": false,    
    "TtlSeconds": 30  
  },  
  "DisableCacheAuthorizationHeader": true  // ← 关键:忽略 Authorization 头
}

⚠️ 仅对无敏感数据的公开接口启用!

6.4 集成 Redis 实现分布式缓存

单机内存缓存在多实例网关部署下失效。需使用Redis统一缓存存储。

步骤 1:安装 Redis 缓存提供者

dotnet add package Ocelot.Provider.Redis

注意:此包同时支持限流和缓存的 Redis 集成。

步骤 2:注册 Redis 缓存服务

Program.cs中:

builder.Services.AddOcelot(builder.Configuration)  
                .AddConsul()  
                .AddRedisRateLimiting()      // 限流用 Redis  
                .AddRedisCache();            // ← 缓存用 Redis

步骤 3:配置 Redis 连接(复用之前限流的配置)

确保appsettings.json包含:

{  
  "ConnectionStrings": {    
    "Redis": "localhost:6379"  
  }
}

步骤 4:验证分布式缓存

  1. 启动两个 Ocelot 实例(端口 5000 和 5001)
  2. 请求实例 A:curl http://localhost:5000/api/products/1
  3. 请求实例 B:curl http://localhost:5001/api/products/1
  4. 观察 ProductService 日志:第二次请求不应触发后端调用

✅ 缓存跨实例共享!

6.5 缓存与认证、限流的协同

场景:公开商品接口 + 私有用户接口

"Routes": [  
  {    
    "UpstreamPathTemplate": "/api/products/{id}",    
    "DownstreamPathTemplate": "/products/{id}",    
    "UpstreamHttpMethod": [ "Get" ],    
    "FileCacheOptions": { "TtlSeconds": 60 },    
    "AuthenticationOptions": null  // 无需认证  
  },  
  {    
    "UpstreamPathTemplate": "/api/users/me",    
    "DownstreamPathTemplate": "/profile",    
    "UpstreamHttpMethod": [ "Get" ],    
    "AuthenticationOptions": { "AuthenticationProviderKey": "Bearer" },    
    "FileCacheOptions": { "TtlSeconds": 10 }  // 短缓存,且按用户隔离  
  }
]
  • 商品接口:所有用户共享缓存,高性能
  • 用户接口:每个用户独立缓存,兼顾安全与性能

6.6 缓存失效策略

Ocelot不支持主动失效(如“商品更新时清除缓存”)。常用方案:

方案 1:缩短 TTL

  • 设置较短缓存时间(如 10~30 秒)
  • 接受短暂数据不一致

方案 2:版本化路径

  • 更新数据时,改变 API 路径或查询参数
    GET /api/products/123?v=2

方案 3:自定义缓存中间件(高级)

  • 在 Ocelot 前插入中间件,监听业务事件(如 RabbitMQ 消息),调用 Redis 清除指定 Key

🔜 后续可扩展章节介绍。

6.7 性能监控建议

  • 记录缓存命中率:命中数 / (命中数 + 未命中数)
  • 监控缓存大小与内存占用
  • 对比开启缓存前后的后端 QPS 与延迟

可通过自定义中间件或集成 Application Insights 实现。

6.8 小结

本章我们实现了:

  • 路由级响应缓存配置
  • 理解缓存键生成逻辑与安全设计
  • 集成 Redis 支持分布式缓存
  • 协同认证、限流构建分层优化策略

现在,我们的网关不仅能防护系统,还能加速响应,真正成为微服务架构的性能中枢。

第七章:Ocelot 生产部署与监控体系搭建

在开发环境中运行良好的 Ocelot 网关,要真正支撑线上业务,还需经过生产级加固。本章将聚焦于可运维性(Operability)可观测性(Observability),涵盖以下关键实践:

  • 容器化部署(Docker + Docker Compose)
  • 配置热更新(避免重启网关)
  • 日志集中收集(结构化日志 + ELK/Serilog)
  • 指标暴露与监控(Prometheus + Grafana)
  • 健康检查与就绪探针(Kubernetes 就绪)

目标:构建一个高可用、易维护、可监控的 API 网关。

7.1 容器化部署:Docker 化 Ocelot 网关

步骤 1:创建 Dockerfile

ApiGateway项目根目录下创建Dockerfile

# 构建阶段
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app/publish
# 运行阶段
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY --from=build /app/publish .
EXPOSE 80
ENTRYPOINT ["dotnet", "ApiGateway.dll"]

✅ 使用多阶段构建减小镜像体积。

步骤 2:构建并运行镜像

# 构建
docker build -t api-gateway .
# 运行(假设 Consul 和 Redis 已在 localhost 可访问)
docker run -d \
  --name gateway \
  -p 5000:80 \
  --network host \  # 或使用自定义 bridge 网络
  api-gateway

🔒 生产建议:使用 Docker Compose 或 Kubernetes 管理依赖服务(Consul、Redis)。

7.2 配置热更新:无需重启加载新路由

Ocelot 支持通过Administration API动态更新配置,避免服务中断。

步骤 1:启用管理端点

ocelot.jsonGlobalConfiguration中添加:

"GlobalConfiguration": {  
  "AdministrationPath": "/administration",  
  "RequestIdKey": "OcRequestId"
}

步骤 2:设置管理密钥(安全必需)

Program.cs中配置认证:

builder.Services.AddOcelot(builder.Configuration)  
                .AddAdministration("/administration",   
                  // 简单示例:使用固定 token  
                  context => context.Response.WriteAsync("Unauthorized"),   
                  secret: "admin-secret-key");

🛡️ 生产环境应集成 OAuth2 或 API Key 验证。

步骤 3:动态更新配置

  1. 修改本地 ocelot.json
  2. 发送 POST 请求更新:
    curl -X POST http://localhost:5000/administration/configuration \  
    -H "Authorization: admin-secret-key" \  
    -H "Content-Type: application/json" \  
    -d @ocelot.json

    ✅ 网关立即生效,无需重启

💡 可结合配置中心(如 Consul KV、Azure App Configuration)实现自动推送。

7.3 结构化日志:集成 Serilog

Ocelot 默认日志较简略。使用Serilog实现结构化、可查询的日志。

步骤 1:安装包

dotnet add package Serilog.AspNetCore
dotnet add package Serilog.Sinks.Console
dotnet add package Serilog.Sinks.File

步骤 2:配置 Serilog(Program.cs)

using Serilog;
var builder = WebApplication.CreateBuilder(args);
// 初始化 Serilog
Log.Logger = new LoggerConfiguration()  
    .WriteTo.Console()  
    .WriteTo.File("logs/gateway-.txt", rollingInterval: RollingInterval.Day)  
    .Enrich.FromLogContext()  
    .CreateBootstrapLogger();
builder.Host.UseSerilog(); // 替换默认日志
// 其他配置...
builder.Configuration.AddJsonFile("ocelot.json");
builder.Services.AddOcelot(builder.Configuration);
// ...

步骤 3:启用 Ocelot 详细日志

appsettings.json中:

{  
  "Logging": {    
    "LogLevel": {      
      "Ocelot": "Information",      
      "Default": "Warning"    
    }  
  }
}

📊 日志包含:请求 ID、上游/下游路径、耗时、状态码,便于追踪链路。

7.4 指标暴露:集成 Prometheus

通过指标监控网关性能(QPS、延迟、错误率)。

步骤 1:安装 Prometheus 支持

dotnet add package prometheus-net.AspNetCore

步骤 2:启用指标端点

Program.cs中:

// 在 app.Run() 之前
app.UseMetricServer(); // 暴露 /metrics 端点
app.UseHttpMetrics();  // 自动收集 HTTP 指标

步骤 3:访问指标

curl http://localhost:5000/metrics

输出示例:

http_request_duration_seconds_bucket{method="GET",status="200",le="0.1"} 5
http_requests_received_total{method="GET",status="429"} 2

步骤 4:配置 Prometheus 抓取

prometheus.yml

scrape_configs:  
  - job_name: 'ocelot-gateway'    
    static_configs:      
      - targets: ['host.docker.internal:5000']  # Docker 访问宿主机

步骤 5:Grafana 可视化

导入ASP.NET Core Dashboard或自定义面板,监控:

  • 请求速率(Requests/sec)
  • 延迟分布(P50/P95/P99)
  • 错误率(4xx/5xx)
  • 缓存命中率(需自定义指标)

🔜 高级:通过IMetricsFactory扩展 Ocelot 特有指标(如熔断状态)。

7.5 健康检查与就绪探针

确保 Kubernetes 或负载均衡器能正确判断网关状态。

步骤 1:启用 ASP.NET Core 健康检查

builder.Services.AddHealthChecks()  
    .AddCheck("self", () => HealthCheckResult.Healthy());
// 在中间件管道中
app.MapHealthChecks("/health/ready"); // 就绪检查
app.MapHealthChecks("/health/live");  // 存活检查

步骤 2:Kubernetes 配置示例(deployment.yaml)

livenessProbe:  
  httpGet:    
    path: /health/live    
    port: 80  
  initialDelaySeconds: 10
readinessProbe:  
  httpGet:    
    path: /health/ready    
    port: 80  
  initialDelaySeconds: 5

✅ 网关启动完成且依赖服务(Consul/Redis)可达时,才接收流量。

7.6 生产部署架构建议

Client   
│   
▼
[Load Balancer] (e.g., AWS ALB, Nginx)   
│   
▼
[Ocelot Gateway Cluster] ←──┐   
│                         │   
├── Consul (服务发现)     │   
├── Redis (限流+缓存)     │   
└── Prometheus (监控)     │  
                          │
[Downstream Services] ◄────┘

关键实践

  • 多实例部署:至少 2 个 Ocelot 实例,避免单点故障
  • 配置版本管理:ocelot.json 纳入 Git,配合 CI/CD
  • Secret 管理:JWT 密钥、Redis 密码使用环境变量或 Vault
  • 网络隔离:网关与后端服务部署在同一 VPC,禁止公网直连

7.7 小结

本章我们完成了 Ocelot 的生产级落地:

  • Docker 容器化部署
  • 配置热更新能力
  • 结构化日志(Serilog)
  • 指标暴露(Prometheus + Grafana)
  • 健康检查支持 Kubernetes

现在,你的 Ocelot 网关已具备企业级微服务网关的完整能力。

整篇总结

我们从零开始,逐步构建了一个功能完备的 API 网关:

能力 技术方案
路由转发 Ocelot 基础配置
服务发现 Consul + 动态负载均衡
统一认证 JWT Bearer + Claims 透传
流量防护 限流(Redis) + 熔断(Polly)
性能优化 响应缓存(内存/Redis)
生产运维 Docker + Prometheus + Serilog + 热更新



上一篇:UDP组播接收原理深度解析:端口绑定与带宽优化实战
下一篇:MySQL GROUP BY 和 ORDER BY 性能优化实战:索引策略与避坑指南
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-12 02:46 , Processed in 0.241675 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表