• Asp .Net Core 系列:集成 Ocelot+Consul+Swagger+Cors实现网关、服务注册、服务发现


    什么是Ocelot?

    Ocelot是一个开源的ASP.NET Core微服务网关,它提供了API网关所需的所有功能,如路由、认证、限流、监控等。

    Ocelot是一个简单、灵活且功能强大的API网关,它可以与现有的服务集成,并帮助您保护、监控和扩展您的微服务。

    以下是Ocelot的一些主要功能:

    1. 路由管理:Ocelot允许您定义路由规则,将请求路由到正确的微服务。
    2. 认证和授权:Ocelot支持多种认证机制,如JWT、OAuth等,并允许您定义访问控制策略,确保只有授权的用户才能访问特定的API。
    3. 限流和速率限制:Ocelot提供了一些内置的限流和速率限制功能,以确保您的服务不会受到过度的请求压力。
    4. 监控和日志:Ocelot可以收集和显示各种度量指标,帮助您了解您的服务的性能和行为。此外,它还可以将日志记录到各种日志源,以便您进行分析和故障排除。
    5. 集成:Ocelot可以与现有的服务集成,包括Kubernetes、Consul等。
    6. 易于扩展:Ocelot的设计使其易于扩展,您可以编写自己的中间件来处理特定的逻辑,例如修改请求或响应、添加自定义的认证机制等。
    7. 可扩展的配置:Ocelot使用JSON配置文件进行配置,这意味着您可以轻松地根据需要进行配置更改,而无需重新编译代码。

    总之,Ocelot是一个功能强大且易于使用的API网关,可以帮助您保护、监控和扩展您的微服务。

    Asp .Net Core 集成 Ocelot

    要在ASP.NET Core中集成Ocelot,您可以按照以下步骤进行操作:

    1. 安装Ocelot NuGet包:
      在您的ASP.NET Core项目中,打开终端或NuGet包管理器控制台,并运行以下命令来安装Ocelot的NuGet包:
    dotnet add package Ocelot
    
    1. 添加Ocelot配置文件:
    {  
      "Routes": [ //这里注意一下版本(旧版本用ReRoutes)
        {
          "DownstreamPathTemplate": "/api/{controller}", //下游路径模板
          "DownstreamScheme": "http", //下游方案
          //"DownstreamHostAndPorts": [
          //  {
          //    "Host": "localhost",
          //    "Port": "5014"
          //  }
          //], //下游主机和端口
          "UpstreamPathTemplate": "/api/product/{controller}", //上游路径模板
          "UpstreamHttpMethod": [], //上游请求方法,可以设置特定的 HTTP 方法列表或设置空列表以允许其中任何方法
          "ServiceName": "api-product-service", //请求服务名称
          "LoadBalancerOptions": {
            "Type": "LeastConnection" //负载均衡算法:目前 Ocelot 有RoundRobin 和LeastConnection算法
          }
        }
      ],
      "GlobalConfiguration": {
        "BaseUrl": "http://localhost:5015", //进行标头查找和替换以及某些管理配置
        "ServiceDiscoveryProvider": {
          "Scheme": "http",
          "Host": "127.0.0.1", //你的Consul的ip地址
          "Port": 8500, //你的Consul的端口
          "Type": "Consul" //类型
          //"ConfigurationKey": "Consul" //指定配置键,键入您的配置
        }
      }
    }
    
    1. 配置Ocelot服务:
    builder.Services.AddOcelot();
    

    Configure方法中配置请求管道并添加Ocelot中间件:

    app.UseOcelot().Wait();
    

    Ocelot 集成 Consul

    要将Ocelot集成到Consul中,您可以按照以下步骤进行操作:

    1. 安装依赖项:
      在您的ASP.NET Core项目中,安装Ocelot和Consul的NuGet包。您可以使用以下命令来安装这些包:
    dotnet add package Ocelot.Provider.Consul
    
    1. 配置Ocelot:
      在Ocelot的配置中,您需要指定Consul作为服务发现和配置的提供者。在Ocelot的配置文件(例如appsettings.json)中,添加以下内容:
    {  
      "GlobalConfiguration": {
        "BaseUrl": "http://localhost:5015", //进行标头查找和替换以及某些管理配置
        "ServiceDiscoveryProvider": {
          "Scheme": "http",
          "Host": "127.0.0.1", //你的Consul的ip地址
          "Port": 8500, //你的Consul的端口
          "Type": "Consul" //类型
          //"ConfigurationKey": "Consul" //指定配置键,键入您的配置
        }
      } 
    }
    

    确保将ConsulHostConsulPort设置为Consul服务器的正确地址和端口。

    1. 启动Ocelot:
      在您的ASP.NET Core应用程序中启动Ocelot。您可以在Startup.cs文件中添加以下代码:
    builder.Services.AddOcelot().AddConsul(); 
    

    全部代码

    Consul相关代码

    namespace MCode.Common.Extensions.Consul
    {
        public class ConsulOptions
        {
            /// 
            /// 当前应用IP
            /// 
            public string IP { get; set; }
    
            /// 
            /// 当前应用端口
            /// 
            public int Port { get; set; }
    
            /// 
            /// 当前服务名称
            /// 
            public string ServiceName { get; set; }
    
            /// 
            /// Consul集群IP
            /// 
            public string ConsulIP { get; set; }
    
            /// 
            /// Consul集群端口
            /// 
            public int ConsulPort { get; set; }
    
            /// 
            /// 权重
            /// 
            public int? Weight { get; set; }
        }
    }
    
    using Consul.AspNetCore;
    using Consul;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Configuration;
    using Microsoft.AspNetCore.Builder;
    
    namespace MCode.Common.Extensions.Consul
    {
        public static class ConsulServiceExtensions
        {
            /// 
            /// 向容器中添加Consul必要的依赖注入
            /// 
            /// 
            /// 
            /// 
            public static IServiceCollection AddMCodeConsul(this IServiceCollection services)
            {
                var configuration = services.BuildServiceProvider().GetRequiredService();
                // 配置consul服务注册信息
                var consulOptions = configuration.GetSection("Consul").Get();
                // 通过consul提供的注入方式注册consulClient
                services.AddConsul(options => options.Address = new Uri($"http://{consulOptions.ConsulIP}:{consulOptions.ConsulPort}"));
    
                // 通过consul提供的注入方式进行服务注册
                var httpCheck = new AgentServiceCheck()
                {
                    DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后注册
                    Interval = TimeSpan.FromSeconds(10),//健康检查时间间隔,或者称为心跳间隔
                    HTTP = $"http://{consulOptions.IP}:{consulOptions.Port}/health",//健康检查地址
                    Timeout = TimeSpan.FromSeconds(10)
                };
    
                // Register service with consul
                services.AddConsulServiceRegistration(options =>
                {
                    options.Checks = new[] { httpCheck };
                    options.ID = Guid.NewGuid().ToString();
                    options.Name = consulOptions.ServiceName;
                    options.Address = consulOptions.IP;
                    options.Port = consulOptions.Port;
                    options.Meta = new Dictionary<string, string>() { { "Weight", consulOptions.Weight.HasValue ? consulOptions.Weight.Value.ToString() : "1" } };
                    options.Tags = new[] { $"urlprefix-/{consulOptions.ServiceName}" }; //添加
                });
    
                return services;
            }
    
            /// 
            /// 配置Consul检查服务
            /// 
            /// 
            /// 
            public static IApplicationBuilder UseConsulCheckService(this IApplicationBuilder app)
            {
                app.Map("/health", app =>
                {
                    app.Run(async context =>
                    {
                        await Task.Run(() => context.Response.StatusCode = 200);
                    });
                });
    
                return app;
            }
        }
    }
    

    Cors

    using Microsoft.AspNetCore.Builder;
    using Microsoft.Extensions.DependencyInjection;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace MCode.Common.Extensions.Cors
    {
        public static class CorsServiceExtensions
        {
            private readonly static string PolicyName = "MCodeCors";
    
            /// 
            /// 添加跨域
            /// 
            /// 服务集合
            /// 
            public static IServiceCollection AddMCodeCors(this IServiceCollection services)
            {
                if (services == null) throw new ArgumentNullException(nameof(services));
                //origin microsoft.aspnetcore.cors      
                return services.AddCors(options =>
                {
                    options.AddPolicy(PolicyName, policy =>
                    {
                        policy.SetIsOriginAllowed(_ => true).AllowAnyMethod().AllowAnyHeader().AllowCredentials();
                    });
                });
            }
            /// 
            /// 使用跨域
            /// 
            /// 应用程序建造者
            /// 
            public static IApplicationBuilder UseMCodeCors(this IApplicationBuilder app)
            {
                return app.UseCors(PolicyName);
            }
        }
    }
    

    Swagger

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace MCode.Common.Extensions.Swagger
    {
        /// 
        /// 网关Swagger配置
        /// 
        public class OcelotSwaggerOptions
        {
            public List SwaggerEndPoints { get; set; }
        }
    }
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace MCode.Common.Extensions.Swagger
    {
        /// 
        /// 网关Swagger配置
        /// 
        public class OcelotSwaggerOptions
        {
            public List SwaggerEndPoints { get; set; }
        }
    }
    
    using Microsoft.OpenApi.Models;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace MCode.Common.Extensions.Swagger
    {
        /// 
        /// Swagger配置
        /// 
        public class SwaggerOptions
        {
            /// 
            /// 服务名称
            /// 
            public string ServiceName { get; set; }
    
            /// 
            /// API信息
            /// 
            public OpenApiInfo ApiInfo { get; set; }
    
            /// 
            /// Xml注释文件
            /// 
            public string[] XmlCommentFiles { get; set; }
    
            /// 
            /// 构造函数
            /// 
            /// 服务名称
            /// API信息
            /// Xml注释文件
            public SwaggerOptions(string serviceName, OpenApiInfo apiInfo, string[] xmlCommentFiles = null)
            {
                ServiceName = !string.IsNullOrWhiteSpace(serviceName) ? serviceName : throw new ArgumentException("serviceName parameter not config.");
                ApiInfo = apiInfo;
                XmlCommentFiles = xmlCommentFiles;
            }
        }
    }
    
    using Microsoft.AspNetCore.Builder;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.OpenApi.Models;
    
    namespace MCode.Common.Extensions.Swagger
    {
        /// 
        /// Swagger 服务扩展
        /// 
        public static class SwaggerServiceExtensions
        {
            /// 
            /// 添加 Swagger 服务
            /// 
            /// 
            /// 
            /// 
            public static IServiceCollection AddMCodeSwagger(this IServiceCollection services, SwaggerOptions swaggerOptions)
            {
                services.AddSingleton(swaggerOptions);
    
                SwaggerGenServiceCollectionExtensions.AddSwaggerGen(services, c =>
                {
                    c.SwaggerDoc(swaggerOptions.ServiceName, swaggerOptions.ApiInfo);
    
                    if (swaggerOptions.XmlCommentFiles != null)
                    {
                        foreach (string xmlCommentFile in swaggerOptions.XmlCommentFiles)
                        {
                            string str = Path.Combine(AppContext.BaseDirectory, xmlCommentFile);
                            if (File.Exists(str)) c.IncludeXmlComments(str, true);
                        }
                    }
    
                    SwaggerGenOptionsExtensions.CustomSchemaIds(c, x => x.FullName);
    
                    c.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme
                    {
                        Type = SecuritySchemeType.Http,
                        Scheme = "bearer",
                        BearerFormat = "JWT",
                        Description = "请输入 bearer 认证"
                    });
    
    
                    c.AddSecurityRequirement(new OpenApiSecurityRequirement
                                                  {
                                                      {
                                                          new OpenApiSecurityScheme
                                                          {
                                                              Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "bearerAuth" }
                                                          },
                                                          new string[] {}
                                                      }
                                                  });
                });
    
                return services;
            }
    
            /// 
            /// 使用 Swagger UI
            /// 
            /// 
            /// 
            public static IApplicationBuilder UseMCodeSwagger(this IApplicationBuilder app)
            {
                string serviceName = app.ApplicationServices.GetRequiredService().ServiceName;
    
                SwaggerUIBuilderExtensions.UseSwaggerUI(SwaggerBuilderExtensions.UseSwagger(app), c =>
                {
                    c.SwaggerEndpoint("/swagger/" + serviceName + "/swagger.json", serviceName);
                });
                return app;
            }
    
    
            public static IServiceCollection AddMCodeOcelotSwagger(this IServiceCollection services, OcelotSwaggerOptions ocelotSwaggerOptions)
            {
                services.AddSingleton(ocelotSwaggerOptions);
                SwaggerGenServiceCollectionExtensions.AddSwaggerGen(services);
                return services;
            }
    
            public static IApplicationBuilder UseMCodeOcelotSwagger(this IApplicationBuilder app)
            {
                OcelotSwaggerOptions ocelotSwaggerOptions = app.ApplicationServices.GetService();
    
                if (ocelotSwaggerOptions == null || ocelotSwaggerOptions.SwaggerEndPoints == null)
                {
                    return app;
                }
    
                SwaggerUIBuilderExtensions.UseSwaggerUI(SwaggerBuilderExtensions.UseSwagger(app), c =>
                {
                    foreach (SwaggerEndPoint swaggerEndPoint in ocelotSwaggerOptions.SwaggerEndPoints)
                    {
                        c.SwaggerEndpoint(swaggerEndPoint.Url, swaggerEndPoint.Name);
                    }
                });
                return app;
            }
        }
    }
    

    MCode.ApiGateway.Program

    using MCode.Common.Extensions.Swagger;
    using MCode.Common.Extensions.Consul;
    using MCode.Common.Extensions.Cors;
    using Ocelot.DependencyInjection;
    using Ocelot.Middleware;
    using Ocelot.Provider.Consul;
    using Microsoft.AspNetCore.Hosting;
    
    var builder = WebApplication.CreateBuilder(args);
    
    builder.WebHost.UseUrls(builder.Configuration.GetValue<string>("Url") ?? "");
    
    //builder.Configuration.SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("ocelot.json", false, true);
    
    // Add services to the container.
    builder.Services.AddMCodeConsul();
    
    builder.Services.AddMCodeCors();
    
    builder.Services.AddMCodeOcelotSwagger(new OcelotSwaggerOptions { SwaggerEndPoints = new List { new SwaggerEndPoint { Name = "api-product-service", Url= "http://localhost:5014/swagger/api-product-service/swagger.json" } } });
    
    builder.Services.AddOcelot().AddConsul();
    
    builder.Services.AddControllers();
    
    var app = builder.Build();
    
    app.UseMCodeCors();
    
    app.UseMCodeOcelotSwagger();
    
    app.UseConsulCheckService();
    
    // Configure the HTTP request pipeline.
    
    app.UseAuthorization();
    
    app.UseOcelot().Wait();
    
    app.Run();
    

    appsettings.json

    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
        }
      },
      "Routes": [ //这里注意一下版本(旧版本用ReRoutes)
        {
          "DownstreamPathTemplate": "/api/{controller}", //下游路径模板
          "DownstreamScheme": "http", //下游方案
          //"DownstreamHostAndPorts": [
          //  {
          //    "Host": "localhost",
          //    "Port": "5014"
          //  }
          //], //下游主机和端口
          "UpstreamPathTemplate": "/api/product/{controller}", //上游路径模板
          "UpstreamHttpMethod": [], //上游请求方法,可以设置特定的 HTTP 方法列表或设置空列表以允许其中任何方法
          "ServiceName": "api-product-service", //请求服务名称
          "LoadBalancerOptions": {
            "Type": "LeastConnection" //负载均衡算法:目前 Ocelot 有RoundRobin 和LeastConnection算法
          }
        }
      ],
      "GlobalConfiguration": {
        "BaseUrl": "http://localhost:5015", //进行标头查找和替换以及某些管理配置
        "ServiceDiscoveryProvider": {
          "Scheme": "http",
          "Host": "127.0.0.1", //你的Consul的ip地址
          "Port": 8500, //你的Consul的端口
          "Type": "Consul" //类型
          //"ConfigurationKey": "Consul" //指定配置键,键入您的配置
        }
      },
      "Url": "http://localhost:5015",
      "Consul": {
        "ConsulIP": "127.0.0.1",
        "ConsulPort": "8500",
        "ServiceName": "api-gateway",
        "Ip": "localhost",
        "Port": "5015",
        "Weight": 1
      },
      "AllowedHosts": "*"
    }
    

    MCode.Product.Api.Program

    using MCode.Product.Api;
    using MCode.Common.Extensions.Consul;
    using MCode.Common.Extensions.Cors;
    using MCode.Common.Extensions.Swagger;
    
    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    
    builder.WebHost.UseUrls(builder.Configuration.GetValue<string>("Url") ?? "");
    
    builder.Services.AddControllers();
    
    builder.Services.AddMCodeConsul();
    
    builder.Services.AddMCodeCors();
    
    builder.Services.AddMCodeSwagger(new SwaggerOptions("api-product-service", new Microsoft.OpenApi.Models.OpenApiInfo { Title = "产品服务" }, new string[] { "MCode.Product.Api.xml" }));
    
    
    var app = builder.Build();
    
    app.UseAuthorization();
    
    
    app.UseMCodeCors();
    
    app.UseMCodeSwagger();
    
    app.UseConsulCheckService();
    
    
    app.MapControllers();
    
    app.Run();
    

    appsettings.json

    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
        }
      },
      "AllowedHosts": "*",
      "Url": "http://localhost:5014",
      "Consul": {
        "ConsulIP": "127.0.0.1",
        "ConsulPort": "8500",
        "ServiceName": "api-product-service",
        "Ip": "localhost",
        "Port": "5014",
        "Weight": 1
      }
    }
    

    效果

    image

    image

  • 相关阅读:
    十种排序方法
    【SQL屠夫系列】- 高频面试之SQL计算用户留存率
    Flink内部数据交换源码分析(一)
    【webrtc】PacketBuffer的VCMPacket管理
    基于AvaSpe 2048测定物体的光谱曲线
    EmEditor文本编辑器添加宏,实现xml报文格式化显示
    基于yolov7与arduino的眼睛跟随模块
    Rust结构体和枚举
    牛客网刷题——JAVA
    【译】.NET 7 中的性能改进(十二)
  • 原文地址:https://www.cnblogs.com/vic-tory/p/17968857