Asp.Net Core API网关Ocelot

首先,让我们简单了解下什么是API网关?

      API网关是一个服务器,是系统的唯一入口。从面向对象设计的角度看,它与外观模式类似。API网关封装了系统内部架构,为每个客户端提供一个定制的API。它可能还具有其它职责,如身份验证、监控、负载均衡、缓存、请求分片与管理、静态响应处理。
    API网关方式的核心要点是,所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有的非业务功能。通常,网关也是提供REST/HTTP的访问API。服务端通过API-GW注册和管理服务。

其次,我们了解下Ocelot框架

 Ocelot的目标是使用.NET运行微服务/面向服务架构,我们需要一个统一的入口进入我们的服务,提供监控、鉴权、负载均衡等机制,也可以通过编写中间件的形式,来扩展Ocelot的功能。  Ocelot是一堆特定顺序的中间件。

 Ocelot框架内部集成了IdentityServer和Consul(服务注册发现),还引入了Polly来处理进行故障处理,关于Polly,可以在这篇博客中了解更多《已被.NET基金会认可的弹性和瞬态故障处理库Polly介绍》

 Ocelot开源地址:https://github.com/TomPallister/Ocelot

接下来,我们就针对Ocelot的具体用法展开介绍。

这里使用的Ocelot版本为2.0,.Net Core版本2.0

1、搭建Asp.net Core WebApi项目,引用Ocelot.dll。

Nuget控制台,执行Ocelot安装。

PM>Install-Package Ocelot

  

GET https://api.nuget.org/v3/registration3-gz-semver2/ocelot/index.json
  OK https://api.nuget.org/v3/registration3-gz-semver2/ocelot/index.json 104 毫秒
  GET https://api.nuget.org/v3/registration3-gz-semver2/ocelot/page/1.5.0-unstable0134/2.0.0.json
  OK https://api.nuget.org/v3/registration3-gz-semver2/ocelot/page/1.5.0-unstable0134/2.0.0.json 108 毫秒
正在还原 J:\Demo\RichCodeBox\APIGatewayApp\APIGatewayApp.csproj 的包...
  GET https://api.nuget.org/v3-flatcontainer/ocelot/index.json
  OK https://api.nuget.org/v3-flatcontainer/ocelot/index.json 476 毫秒
  GET https://api.nuget.org/v3-flatcontainer/ocelot/2.0.0/ocelot.2.0.0.nupkg
  OK https://api.nuget.org/v3-flatcontainer/ocelot/2.0.0/ocelot.2.0.0.nupkg 125 毫秒
  GET https://api.nuget.org/v3-flatcontainer/identityserver4.accesstokenvalidation/index.json
  GET https://api.nuget.org/v3-flatcontainer/cachemanager.core/index.json
  GET https://api.nuget.org/v3-flatcontainer/cachemanager.microsoft.extensions.configuration/index.json
  GET https://api.nuget.org/v3-flatcontainer/cachemanager.microsoft.extensions.logging/index.json
  GET https://api.nuget.org/v3-flatcontainer/consul/index.json
  GET https://api.nuget.org/v3-flatcontainer/polly/index.json
  GET https://api.nuget.org/v3-flatcontainer/identityserver4/index.json
  OK https://api.nuget.org/v3-flatcontainer/identityserver4.accesstokenvalidation/index.json 133 毫秒
  GET https://api.nuget.org/v3-flatcontainer/identityserver4.accesstokenvalidation/2.1.0/identityserver4.accesstokenvalidation.2.1.0.nupkg
  OK https://api.nuget.org/v3-flatcontainer/cachemanager.microsoft.extensions.logging/index.json 286 毫秒
  OK https://api.nuget.org/v3-flatcontainer/polly/index.json 287 毫秒
  OK https://api.nuget.org/v3-flatcontainer/identityserver4.accesstokenvalidation/2.1.0/identityserver4.accesstokenvalidation.2.1.0.nupkg 160 毫秒
  GET https://api.nuget.org/v3-flatcontainer/cachemanager.microsoft.extensions.logging/1.1.1/cachemanager.microsoft.extensions.logging.1.1.1.nupkg

  2、修改Startup程序。

   /// <summary>
        ///
        /// </summary>
        /// <param name="environment"></param>
        public Startup(IHostingEnvironment environment)
        {
            var builder = new Microsoft.Extensions.Configuration.ConfigurationBuilder();
            builder.SetBasePath(environment.ContentRootPath)
                   .AddJsonFile("appsettings.json", false, reloadOnChange: true)
                   .AddJsonFile($"appsettings.{environment.EnvironmentName}.json", optional: false, reloadOnChange: true)
                   .AddJsonFile("configuration.json", optional: false, reloadOnChange: true)
                   .AddEnvironmentVariables();

            Configuration = builder.Build();
        }

  

        /// <summary>
        ///modified:配置
        /// </summary>
        public IConfigurationRoot Configuration { get; }

        /// <summary>
        /// 配置服务
        /// </summary>
        /// <param name="services"></param>
        public void ConfigureServices(IServiceCollection services)
        {
            Action<ConfigurationBuilderCachePart> settings = (x) =>
            {
                x.WithMicrosoftLogging(log =>
                {
                    log.AddConsole(LogLevel.Debug);

                }).WithDictionaryHandle();
            };
            services.AddOcelot(Configuration, settings);
            //services.AddMvc();
        }

        /// <summary>
        /// 配置Ocelot
        /// </summary>
        /// <param name="app"></param>
        /// <param name="env"></param>
        public async void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            //if (env.IsDevelopment())
            //{
            //    app.UseDeveloperExceptionPage();
            //}
            await app.UseOcelot();
            //app.UseMvc();
        }
        /// <summary>
        /// 入口程序
        /// </summary>
        /// <param name="args"></param>
        public static void Main(string[] args)
        {
            IWebHostBuilder builder = new WebHostBuilder();
            builder.ConfigureServices(s =>
            {
                s.AddSingleton(builder);
            });
            builder.UseKestrel()
                   .UseContentRoot(Directory.GetCurrentDirectory())
                   .UseIISIntegration()
                   .UseStartup<Startup>()
                   .UseApplicationInsights();
            var host = builder.Build();
            host.Run();
        }

  

3、配置Ocelot。

我们新建一个名为configuration的json文件,配置如下:

{
  "ReRoutes": [
    {
      "DownstreamPathTemplate": "/api/values",
      "DownstreamScheme": "http",
      "DownstreamHost": "localhost",
      "DownstreamPort": 8801,
      "UpstreamPathTemplate": "/api/values",
      "UpstreamHttpMethod": [ "Get" ],
      "QoSOptions": {
        "ExceptionsAllowedBeforeBreaking": 3,
        "DurationOfBreak": 10,
        "TimeoutValue": 5000
      },
      "HttpHandlerOptions": {
        "AllowAutoRedirect": false,
        "UseCookieContainer": false
      },
      "AuthenticationOptions": {

      }
    },
    {
      "DownstreamPathTemplate": "/api/product",
      "DownstreamScheme": "http",
      "DownstreamPort": 8802,
      "DownstreamHost": "localhost",
      "UpstreamPathTemplate": "/api/product",
      "UpstreamHttpMethod": [ "Get" ],
      "QoSOptions": {
        "ExceptionsAllowedBeforeBreaking": 3,
        "DurationOfBreak": 10,
        "TimeoutValue": 5000
      },
      "AuthenticationOptions": {

      }
    }
  ],
  "GlobalConfiguration": {
    "RequestIdKey": "OcRequestId",
    "AdministrationPath": "/admin"
  }
}

  

在这里,我们配置了两个服务,端口分别为8801和8802的。

Ocelot支持负载均衡(提供轮询、最少访问)。Ocelot大部分功能,都可以通过中间件来完成,也可以实现和重写中间件。

Ocelot原理非常简单,这里的配置文件,体现了上游请求和下游服务间的映射关系,你可以理解为,上游是客户端直接调用的URL ,下游,则是对应我们开发的服务。

4、新增两个WebApi项目,分别为APIUserServiec和APIProductService。

API服务 端口(Port)
APIUserServiec 8801
APIProductService 8802

解决方案如下:

5、配置VS启动端口:

依次类推,分别设置端口。

6、启动项目。

配置多个项目启动。

F5启动项目。

再通过API网关,访问商品服务:http://localhost:5000/api/product。

常见问题:

首次在启动API网关时,触发以下错误。

Sequence contains no matching element

 

根据错误详细信息,可知原因是由于系统调用AddIdentityServer方法时,触发异常。

刚开始,怀疑是配置文件configuration.json文件配置导致的,Ocelot2.0版,采用官方配置仍然触发该异常,由此排除这种可能。接下来,直接从github上克隆源代码,查看。

找到触发错误的地方,

private static void AddIdentityServer(this IServiceCollection services, IIdentityServerConfiguration identityServerConfiguration, IConfigurationRoot configurationRoot)
        {
            services.TryAddSingleton<IIdentityServerConfiguration>(identityServerConfiguration);
            services.TryAddSingleton<IHashMatcher, HashMatcher>();
            var identityServerBuilder = services
                .AddIdentityServer(o => {
                    o.IssuerUri = "Ocelot";
                })
                .AddInMemoryApiResources(Resources(identityServerConfiguration))
                .AddInMemoryClients(Client(identityServerConfiguration))
                .AddResourceOwnerValidator<OcelotResourceOwnerPasswordValidator>();

            //todo - refactor a method so we know why this is happening
            var whb = services.First(x => x.ServiceType == typeof(IWebHostBuilder));//这个地方触发了错误
            var urlFinder = new BaseUrlFinder((IWebHostBuilder)whb.ImplementationInstance);
            var baseSchemeUrlAndPort = urlFinder.Find();
            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

            services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
                .AddIdentityServerAuthentication(o =>
                {
                    var adminPath = configurationRoot.GetValue("GlobalConfiguration:AdministrationPath", string.Empty);
                    o.Authority = baseSchemeUrlAndPort + adminPath;
                    o.ApiName = identityServerConfiguration.ApiName;
                    o.RequireHttpsMetadata = identityServerConfiguration.RequireHttps;
                    o.SupportedTokens = SupportedTokens.Both;
                    o.ApiSecret = identityServerConfiguration.ApiSecret;
                });

                //todo - refactor naming..
                if (string.IsNullOrEmpty(identityServerConfiguration.CredentialsSigningCertificateLocation) || string.IsNullOrEmpty(identityServerConfiguration.CredentialsSigningCertificatePassword))
                {
                    identityServerBuilder.AddDeveloperSigningCredential();
                }
                else
                {
                    //todo - refactor so calls method?
                    var cert = new X509Certificate2(identityServerConfiguration.CredentialsSigningCertificateLocation, identityServerConfiguration.CredentialsSigningCertificatePassword);
                    identityServerBuilder.AddSigningCredential(cert);
                }
var whb = services.First(x => x.ServiceType == typeof(IWebHostBuilder));

这就代码触发了错误,是由于表达式条件不成立,导致First发生异常,这就简单了,我们修改Main函数,

把这句代码:

 var builder = new WebHostBuilder();

改成:

IWebHostBuilder builder = new WebHostBuilder();

这样,就解决了问题,API网关启动成功。另外,官方例子https://github.com/TomPallister/Ocelot/blob/develop/test/Ocelot.ManualTest/Program.cs中,写法是正确的,大家自己写的时候,注意把IWebHostBuilder换成var会引发错误。

这样,使用Ocelot框架搭建API网关的工作已经完成,尝试通过访问API网关,来访问下游的服务。

此实例源码:https://gitee.com/lichaoqiang/RichCodeBox.git

欢迎大家一起研究探讨,开启你的微服务之路。

 

时间: 2024-11-10 11:25:43

Asp.Net Core API网关Ocelot的相关文章

【翻译】在Visual Studio中使用Asp.Net Core MVC创建你的第一个Web API应用(一)

HTTP is not just for serving up web pages. It's also a powerful platform for building APIs that expose services and data. HTTP is simple, flexible, and ubiquitous. Almost any platform that you can think of has an HTTP library, so HTTP services can re

ASP.NET Core 2.0 支付宝当面付之扫码支付

原文:ASP.NET Core 2.0 支付宝当面付之扫码支付 前言 自从微软更换了CEO以后,微软的战略方向有了相当大的变化,不再是那么封闭,开源了许多东西,拥抱开源社区,.NET实现跨平台,收购xamarin并免费提供给开发者等等.我本人是很喜欢.net的,并希望.net core能够崛起.我是从.net core 1.1的时候开始使用的,到现在的.net core 2.0..net core 2.0比1.1有了一些改变,api也增加了很多,用着更顺手了,最近在做asp.net core 对

ASP.NET Core的配置(2):配置模型详解

在上面一章我们以实例演示的方式介绍了几种读取配置的几种方式,其中涉及到三个重要的对象,它们分别是承载结构化配置信息的Configuration,提供原始配置源数据的ConfigurationProvider,以及作为"中间人"的ConfigurationBuilder.接下来我们将会对由这三个核心对象组成的配置模型进行详细介绍,不过在此之前我们有必要来认识配置信息在不同载体中所体现出来的三种结构. 目录 一.配置的三种结构 逻辑结构 原始结构 物理结构 结构转换 二.Configura

ASP.NET Core的路由[5]:内联路由约束的检验

当某个请求能够被成功路由的前提是它满足某个Route对象设置的路由规则,具体来说,当前请求的URL不仅需要满足路由模板体现的路径模式,请求还需要满足Route对象的所有约束.路由系统采用IRouteConstraint接口来表示路由约束,所以我们在接下来的内容中将路由约束统称为RouteConstraint. 在大部分情况下,约束都是针对路由模板中定义的某个路由参数,其目的在于验证URL携带的某部分的内容是否有效.不过也有一些约束与路由参数无关,这些约束规范往往是除URL之前的其他请求元素,比如

ASP.NET Core的配置(1):读取配置信息

提到"配置"二字,我想绝大部分.NET开发人员脑海中会立马浮现出两个特殊文件的身影,那就是我们再熟悉不过的app.config和web.config,多年以来我们已经习惯了将结构化的配置信息定义在这两个文件之中.到了.NET Core的时候,很多我们习以为常的东西都发生了改变,其中也包括定义配置的方式.总的来说,新的配置系统显得更加轻量级,并且具有更好的扩展性,其最大的特点就是支持多样化的数据源.我们可以采用内存的变量作为配置的数据源,也可以直接配置定义在持久化的文件甚至数据库中. 由

ASP.NET Core 折腾笔记一

前言: 在ASP.NET Core 1.0时,曾折腾过一次,后因发现不了System.Data而停止. 更因VS2015提示过期Delete掉VS了,其实主要还是笔记本的硬盘空间吃紧. 快双十一了,本想过重新买台笔本来折腾.NET Core. 睡觉时,莫名脑袋一转,格了系统重来吧,然后就省下一台笔记本的钱了. 花了半天,终于把VS2015环境都装好了,终于又开始作了. VS环境安装过程: 1:Win7系统,要装SP1,才能安装VS2015(安装后6-7个G大小) 2:下载安装VS2015(安装后

ASP.NET Core中的依赖注入(1):控制反转(IoC)

ASP.NET Core在启动以及后续针对每个请求的处理过程中的各个环节都需要相应的组件提供相应的服务,为了方便对这些组件进行定制,ASP.NET通过定义接口的方式对它们进行了"标准化",我们将这些标准化的组件称为服务,ASP.NET在内部专门维护了一个DI容器来提供所需的服务.要了解这个DI容器以及现实其中的服务提供机制,我们先得知道什么是DI(Dependence Injection),而一旦我们提到DI,又不得不说IoC(Inverse of Control). 目录 一.流程控

API网关具备自动生成多语言SDK的能力

API网关为了实现客户端和服务器端之间的安全通讯,设计了全套的签名策略,只有携带通过复杂的签名算法的签名请求头的请求才会被API网关转发给后端服务器,否则请求会被API网关拒绝.这个连接是API签名算法的具体说明:https://help.aliyun.com/document_detail/29475.html,相信大家看到签名算法的介绍,会发现该签名算法有一定的复杂度,实现起来需要花费不少的时间,还需要和网关联调,有一定的工作量. 作为API网关的用户,要想正确得使用API网关的各项能力,就

.NET Core RC2发布在即,我们试着用记事本编写一个ASP.NET Core RC2 MVC程序

在.NET Core 1.0.0 RC2即将正式发布之际,我也应应景,针对RC2 Preview版本编写一个史上最简单的MVC应用.由于VS 2015目前尚不支持,VS Code的智能感知尚欠火候,所以我们直接采用最原始的记事本来编写这个MVC应用.[源代码从这里下载] 目录 步骤一.安装最新的.NET Core SDK 步骤二.定义源代码和配置         定义NuGet.xml         定义Project.json         定义入口程序         定义初始化类型