第一章: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 配置中硬编码每个服务的Host和Port(如"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]
流程:
- 微服务启动时,向 Consul 注册自己(服务名 + 地址 + 健康检查端点)
- Ocelot 配置路由时,不再写死 IP/Port,而是使用 服务名(如 "ServiceName": "user-service")
- Ocelot 定期从 Consul 拉取该服务的所有健康实例
- 请求到来时,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();
🔁 你可以复制此项目,修改端口和服务名为6002、user-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 启动并测试
启动顺序:
- 启动 Consul(Docker 或本地)
- 启动两个 UserService 实例(端口 6001 和 6002)
- 启动 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的控制器中:
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 生产环境建议
- 使用 HTTPS:防止 Token 被窃听
- 密钥管理:不要硬编码密钥,使用 Azure Key Vault / AWS Secrets Manager / 环境变量
- Token 过期时间:设置合理(如 15~60 分钟),配合 Refresh Token 机制
- 认证服务独立化:使用 IdentityServer、Auth0 或自研 OAuth2 Server
- 日志审计:记录认证失败尝试,防范暴力破解
4.9 小结
本章我们实现了:
- 在 Ocelot 网关层集成 JWT Bearer 认证
- 保护特定路由,拒绝未认证请求
- 将用户 Claims 注入请求头,透传身份信息
- 下游服务无感知地获取调用者身份
现在,我们的网关已具备统一安全边界,为后续的限流、缓存、监控等功能奠定基础。
第五章:Ocelot 实现 API 限流与熔断保护
在高并发或恶意攻击场景下,后端微服务可能因请求过载而崩溃。为保障系统稳定性,API 网关需具备流量控制能力。本章将深入讲解 Ocelot 提供的两大核心防护机制:
- 限流(Rate Limiting):限制单位时间内客户端可发起的请求数,防止滥用。
- 熔断(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 |
单个请求最大等待时间(毫秒),超时视为失败 |
测试熔断:
- 启动一个会返回 500 的 order-service
- 连续请求 3 次 /api/orders
- 第 4 次请求将直接返回 503 Service Unavailable(无需等待)
- 等待 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:验证分布式缓存
- 启动两个 Ocelot 实例(端口 5000 和 5001)
- 请求实例 A:curl http://localhost:5000/api/products/1
- 请求实例 B:curl http://localhost:5001/api/products/1
- 观察 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:版本化路径
方案 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.json的GlobalConfiguration中添加:
"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:动态更新配置
- 修改本地 ocelot.json
- 发送 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 + 热更新 |