OcelotAPI基于.NETCore的网关实现

1. Ocelot 简介

Ocelot 是一个基于 .NET Core 的开源 API 网关,专为微服务架构设计。它提供以下核心功能:

  • 请求路由:将客户端请求映射到后端服务
  • 负载均衡:在多个服务实例间分配流量
  • 服务聚合:组合多个后端服务的响应
  • 认证授权:在网关层实现统一安全控制
  • 熔断限流:保护后端服务免受流量冲击

2. 项目结构

Microservices/
├── ValuesService/         # 微服务1 - 提供基础数据
│   ├── Controllers/
│   │   └── ValuesController.cs
│   └── Program.cs
│
├── ProductService/        # 微服务2 - 提供产品数据
│   ├── Controllers/
│   │   └── ProductsController.cs
│   └── Program.cs
│
├── OcelotGateway/         # API网关
│   ├── ocelot.json        # 路由配置
│   ├── Program.cs
│   └── Startup.cs         # 服务配置
│
└── AuthServer/            # 授权服务器
    ├── Config.cs          # 身份配置
    └── Startup.cs

3. 微服务实现

3.1 ValuesService 微服务

ValuesController.cs

[ApiController]
[Route("api/[controller]")]
public class ValuesController : ControllerBase
{
    // 返回简单字符串数组
    [HttpGet]
    public IEnumerable<string> Get()
    {
        var port = HttpContext.Request.Host.Port;
        return new string[] { 
            $"Value1 (from {port})", 
            $"Value2 (from {port})", 
            $"Value3 (from {port})" 
        };
    }
}

启动命令

dotnet run --urls "http://localhost:5001"
dotnet run --urls "http://localhost:5003" # 第二个实例

3.2 ProductService 微服务

ProductsController.cs

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    // 返回产品列表
    [HttpGet]
    public IEnumerable<Product> Get()
    {
        return new List<Product>
        {
            new Product(1, "Laptop", 999.99),
            new Product(2, "Smartphone", 699.99),
            new Product(3, "Tablet", 399.99)
        };
    }
    
    public record Product(int Id, string Name, double Price);
}

启动命令

bash

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

4. API 网关实现

4.1 ocelot.json 配置文件详解

{
  "Routes": [
    {
      // ValuesService 路由配置
      "DownstreamPathTemplate": "/api/values",   // 后端服务实际路径
      "DownstreamScheme": "http",                // 后端服务协议
      "DownstreamHostAndPorts": [                // 后端服务实例列表
        { "Host": "localhost", "Port": 5001 },   // 实例1
        { "Host": "localhost", "Port": 5003 }    // 实例2
      ],
      "UpstreamPathTemplate": "/gateway/values", // 网关暴露路径
      "UpstreamHttpMethod": [ "Get" ],           // 允许的HTTP方法
      "LoadBalancerOptions": {                   // 负载均衡配置
        "Type": "RoundRobin"                     // 轮询策略
      },
      "AuthenticationOptions": {                 // 认证配置
        "AuthenticationProviderKey": "Bearer",   // 认证方案名称
        "AllowAnonymous": false                  // 禁止匿名访问
      },
      "RateLimitOptions": {                      // 限流配置
        "EnableRateLimiting": true,
        "Period": "1s",                          // 时间窗口
        "Limit": 5                               // 请求上限
      }
    },
    {
      // ProductService 路由配置
      "DownstreamPathTemplate": "/api/products",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        { "Host": "localhost", "Port": 5002 }
      ],
      "UpstreamPathTemplate": "/gateway/products",
      "UpstreamHttpMethod": [ "Get" ],
      "AuthenticationOptions": {
        "AuthenticationProviderKey": "Bearer",
        "AllowAnonymous": false
      }
    }
  ],
  "GlobalConfiguration": {
    "BaseUrl": "http://localhost:5000",          // 网关基础URL
    "RequestIdKey": "OcelotRequestId"            // 请求ID标识
  }
}

4.2 Startup.cs 配置详解

public void ConfigureServices(IServiceCollection services)
{
    // 添加Ocelot服务(自动加载ocelot.json)
    services.AddOcelot()
            .AddDelegatingHandler<RequestLoggerHandler>(true); // 自定义日志处理器
    
    // JWT认证配置
    services.AddAuthentication("Bearer")
        .AddJwtBearer("Bearer", options =>
        {
            options.Authority = "https://localhost:5004"; // 授权服务器地址
            options.Audience = "api_gateway";             // API资源名称
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ClockSkew = TimeSpan.Zero // 严格校验过期时间
            };
        });
    
    // 添加内存缓存(用于限流)
    services.AddMemoryCache();
    
    // 添加健康检查
    services.AddHealthChecks();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseRouting();
    
    // 启用跨域
    app.UseCors("GatewayPolicy");
    
    // 认证授权中间件
    app.UseAuthentication();
    app.UseAuthorization();
    
    // 健康检查端点
    app.UseEndpoints(endpoints => 
    {
        endpoints.MapHealthChecks("/health");
    });
    
    // Ocelot中间件
    app.UseOcelot().Wait();
    
    // 自定义中间件:请求日志记录
    app.UseMiddleware<RequestLoggingMiddleware>();
}

4.3 自定义日志处理器

RequestLoggerHandler.cs

public class RequestLoggerHandler : DelegatingHandler
{
    private readonly ILogger<RequestLoggerHandler> _logger;

    public RequestLoggerHandler(ILogger<RequestLoggerHandler> logger)
    {
        _logger = logger;
    }

    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, 
        CancellationToken cancellationToken)
    {
        // 记录请求信息
        _logger.LogInformation($"Gateway Request: {request.Method} {request.RequestUri}");
        
        // 继续处理请求
        var response = await base.SendAsync(request, cancellationToken);
        
        // 记录响应信息
        _logger.LogInformation($"Gateway Response: {(int)response.StatusCode} {response.StatusCode}");
        
        return response;
    }
}

5. 授权服务器实现

5.1 Config.cs (AuthServer)

public static class Config
{
    // API资源定义
    public static IEnumerable<ApiResource> GetApiResources()
    {
        return new List<ApiResource>
        {
            new ApiResource("api_gateway", "API Gateway")
            {
                Scopes = { "gateway.fullaccess" }
            }
        };
    }

    // 客户端定义
    public static IEnumerable<Client> GetClients()
    {
        return new List<Client>
        {
            // 客户端凭证模式
            new Client
            {
                ClientId = "service_client",
                ClientSecrets = { new Secret("service_secret".Sha256()) },
                AllowedGrantTypes = GrantTypes.ClientCredentials,
                AllowedScopes = { "gateway.fullaccess" }
            },
            
            // 密码模式(用于用户登录)
            new Client
            {
                ClientId = "user_client",
                ClientSecrets = { new Secret("user_secret".Sha256()) },
                AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
                AllowedScopes = { "gateway.fullaccess" }
            }
        };
    }
}

5.2 Startup.cs (AuthServer)

public void ConfigureServices(IServiceCollection services)
{
    services.AddIdentityServer()
        .AddDeveloperSigningCredential()
        .AddInMemoryApiResources(Config.GetApiResources())
        .AddInMemoryClients(Config.GetClients())
        .AddTestUsers(TestUsers.Users); // 添加测试用户
}

public void Configure(IApplicationBuilder app)
{
    app.UseIdentityServer();
    
    // 提供发现文档端点
    app.UseEndpoints(endpoints => 
    {
        endpoints.MapGet("/.well-known/openid-configuration", 
            async context => 
            {
                var disco = await context.RequestServices
                    .GetRequiredService<IDiscoveryResponseGenerator>()
                    .GenerateAsync();
                await context.Response.WriteAsJsonAsync(disco);
            });
    });
}

6. 运行与测试

6.1 启动顺序

  1. 启动授权服务器

    cd AuthServer
    dotnet run --urls "https://localhost:5004"
    
  2. 启动微服务

    # ValuesService (两个实例)
    cd ValuesService
    dotnet run --urls "http://localhost:5001"
    dotnet run --urls "http://localhost:5003"
    
    # ProductService
    cd ProductService
    dotnet run --urls "http://localhost:5002"
    
  3. 启动网关

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

6.2 测试场景

获取访问令牌
# 使用客户端凭证模式
curl -X POST https://localhost:5004/connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=service_client&client_secret=service_secret&grant_type=client_credentials&scope=gateway.fullaccess"
通过网关访问服务
# 访问ValuesService(负载均衡)
curl -H "Authorization: Bearer <TOKEN>" http://localhost:5000/gateway/values

# 响应示例(轮询显示不同实例):
# ["Value1 (from 5001)", "Value2 (from 5001)", "Value3 (from 5001)"]
# ["Value1 (from 5003)", "Value2 (from 5003)", "Value3 (from 5003)"]

# 访问ProductService
curl -H "Authorization: Bearer <TOKEN>" http://localhost:5000/gateway/products

# 响应示例:
# [{"id":1,"name":"Laptop","price":999.99}, ...]
测试限流功能
# 快速发送10个请求
for i in {1..10}; do
  curl -s -H "Authorization: Bearer <TOKEN>" \
    -w "HTTP %{http_code}\n" \
    http://localhost:5000/gateway/values -o /dev/null
done

# 预期结果:前5个返回200,后续返回429(Too Many Requests)

7. 高级功能实现

7.1 动态负载均衡

Ocelot 支持多种负载均衡策略:

"LoadBalancerOptions": {
  "Type": "LeastConnection" // 最小连接数策略
}

可用选项:

  • RoundRobin:轮询(默认)
  • LeastConnection:最少连接数
  • CookieStickySessions:会话粘滞
  • NoLoadBalancer:无负载均衡

7.2 服务发现集成

结合 Consul 实现动态服务发现:

"GlobalConfiguration": {
  "ServiceDiscoveryProvider": {
    "Type": "Consul",
    "Host": "localhost",
    "Port": 8500,
    "Token": "<consul_token>"
  }
}

7.3 熔断机制

使用 Polly 实现熔断:

{
  "Routes": [
    {
      // ...其他配置
      "QoSOptions": {
        "ExceptionsAllowedBeforeBreaking": 3, // 允许异常次数
        "DurationOfBreak": 30,                // 熔断时长(秒)
        "TimeoutValue": 5000                  // 超时时间(毫秒)
      }
    }
  ]
}

7.4 请求聚合

创建聚合器:

public class ValuesProductsAggregator : IDefinedAggregator
{
    public async Task<DownstreamResponse> Aggregate(List<HttpContext> responses)
    {
        var values = await responses[0].Items.DownstreamResponse().Content.ReadAsStringAsync();
        var products = await responses[1].Items.DownstreamResponse().Content.ReadAsStringAsync();
        
        var content = new {
            Values = JsonConvert.DeserializeObject(values),
            Products = JsonConvert.DeserializeObject(products)
        };
        
        return new DownstreamResponse(
            new StringContent(JsonConvert.SerializeObject(content)), 
            HttpStatusCode.OK, 
            new HeaderDictionary(), 
            "OK");
    }
}

配置 ocelot.json:

{
  "Routes": [
    {
      "DownstreamPathTemplate": "/api/values",
      "UpstreamPathTemplate": "/values",
      "Key": "Values",
      "UpstreamHttpMethod": ["Get"]
    },
    {
      "DownstreamPathTemplate": "/api/products",
      "UpstreamPathTemplate": "/products",
      "Key": "Products",
      "UpstreamHttpMethod": ["Get"]
    }
  ],
  "Aggregates": [
    {
      "ReRouteKeys": ["Values", "Products"],
      "UpstreamPathTemplate": "/aggregated-data",
      "Aggregator": "ValuesProductsAggregator"
    }
  ]
}

8. 最佳实践

  1. 配置管理
    • 使用环境变量区分开发/生产配置
    • 将敏感数据存储在 Azure Key Vault 或 HashiCorp Vault
    • 启用配置热更新:AddJsonFile("ocelot.json", optional: false, reloadOnChange: true)
  2. 安全加固
    • 启用 HTTPS 终端
    • 使用双向 TLS 认证
    • 限制管理端点访问
  3. 高可用
    • 部署多个网关实例
    • 使用负载均衡器分发流量
    • 实现健康检查端点
  4. 监控日志
    • 集成 Application Insights 或 ELK 栈
    • 记录请求/响应日志
    • 监控关键指标(请求率、延迟、错误率)
  5. 性能优化
    • 启用响应缓存
    • 压缩响应内容
    • 优化JSON序列化

9. 总结

通过本指南,您已实现了一个完整的 Ocelot API 网关解决方案:

  1. 核心路由功能:配置 /gateway/values/gateway/products 路由
  2. 负载均衡:实现 ValuesService 的轮询负载
  3. 安全认证:集成 JWT 认证和授权
  4. 高级特性:实现限流、熔断和请求聚合
  5. 可观测性:添加日志记录和健康检查

Ocelot 网关为微服务架构提供了统一的入口点,有效解决了服务发现、流量管理、安全控制等核心问题。通过灵活的配置和扩展机制,可以满足各种复杂场景的需求。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐