Ocelot的使用

Ocelot的使用:

在ASP.NET Core中集成Ocelot网关

  既然Ocelot是通过Asp.net中间件进行网关管理,那么我们肯定就需要一个Asp.net作为宿主,为了演示DEMO,笔者建立了三个模板为Web API的Asp.net core项目,在其中一个asp.net core里通过nuget即可完成安装和集成Ocelot,或者命令行dotnet add package Ocelot以及通过vs2017 package manager添加Ocelot nuget引用都可以,甚至你还可以跟笔者一样喜欢全家桶系列(VS固然非常强大,甚至宇宙第一,但笔者更喜欢三大平台都一模一样的Jetbrains全家桶),用Rider的Nuget管理来安装Ocelot也可以。

        

  我们把这个网关项目取名为ApiGatway,然后在这个项目的Startup中添加依赖注入和中间件,即可完成Ocelot安装和注入

复制代码

 1 public void ConfigureServices(IServiceCollection services)
 2 {
 3     services.AddOcelot();
 4 }
 5 
 6 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
 7 {
 8     if (env.IsDevelopment())
 9     {
10         app.UseDeveloperExceptionPage();
11     }
12 
13     app.UseOcelot().Wait();
14 }

复制代码

 

添加配置

  我们需要添加一个.json的文件用来添加Ocelot的配置,以下是最基本的配置信息。

复制代码

{
    "ReRoutes": [],
    "GlobalConfiguration": {
        "BaseUrl": "https://api.mybusiness.com"
    }
}

复制代码

  要特别注意一下BaseUrl是我们外部暴露的Url,比如我们的Ocelot运行在http://127.0.0.1的一个地址上(或一个端口上),但是前面有一个Nginx绑定了域名https://api.mybusiness.com,那这里我们的BaseUrl就应该是 https://api.mybusiness.com

 

将配置文件加入ASP.NET Core Configuration

  我们需要通过IWebHostBuilder将我们添加的json文件添加进Asp.net Core中

复制代码

1 public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args)
2         .ConfigureAppConfiguration((hostingContext, builder) =>
3         {
4             builder.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
5                 .AddJsonFile("Ocelot.json");
6         })
7         .UseStartup<Startup>();
8 }

复制代码

 

Ocelot的功能配置介绍

  通过配置文件可以完成对Ocelot的功能配置:路由、服务聚合、服务发现、认证、鉴权、限流、熔断、缓存、Header头传递等。在配置文件中包含两个根节点:ReRoutes和GlobalConfiguration。ReRoutes是一个数组,其中的每一个元素代表了一个路由,我们可以针对每一个路由进行以上功能配置。下面是一个较完整的配置文件,根据笔者的理解,并加上了详细的注释,方便初学者理解。官方路径戳这儿:https://ocelot.readthedocs.io/en/latest/features/configuration.html

复制代码

{
  "ReRoutes": [
    // 路由规则配置节点,数组形式
    // 可配置多个路由协议和规则,实现路由、服务聚合、服务发现、认证、鉴权、限流、熔断、缓存、Header头传递等
    {
      /*
       下游服务配置配置,网关出口,具体指向的服务器
       /api/values - 使用限定规则的方式配置下游PATH规则
       /{url} - 使用泛型(万用)规则方式配置下游PATH规则
       */
      "DownstreamPathTemplate": "/{url}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        /*
        下游主机信息
        可以配置多个主机信息,已提供Ocelot路由负载均衡模式,需配合LoadBalancer节点进行路由负载均衡。
        */
        {
          "Host": "127.0.0.1",
          "Port": 5000
        },
        {
          "Host": "127.0.0.1",
          "Port": 5001
        }
      ],
      /*
       上游服务配置配置,请求和网关的入口。
       /api/values - 使用限定规则的方式配置上游PATH规则
       /{url} - 使用泛型(万用)规则方式配置上游PATH规则
       */
      "UpstreamPathTemplate": "/{url}",
      // 上游支持的http请求方法
      "UpstreamHttpMethod": [
        "Get",
        "Post",
        "Delete",
        "Update"
      ],
      // 上游域名主机
      // "UpstreamHost": "domain.com",
      // 当前路由节点的优先级
      "Priority": 99,
      /*
       路由负载均衡:
       LeastConnection – 将请求发往最空闲的那个服务器
       RoundRobin – 轮流发送
       NoLoadBalance – 总是发往第一个请求或者是服务发现
       */
      "LoadBalancer": "LeastConnection",
      "Key": "Route1",
    }
  ],
  // 限流配置(请求限流)
  // 对请求进行限流可以防止下游服务器因为访问过载而崩溃
  "RateLimitOptions": {
    // ClientWhitelist - 白名单列表
    "ClientWhitelist": [],
    // EnableRateLimiting - 是否启用限流
    "EnableRateLimiting": true,
    // Period - 统计时间段 1s, 5m, 1h, 1d
    "Period": "1s",
    // PeriodTimespan - 多少秒之后客户端可以重试
    "PeriodTimespan": 1,
    // Limit - 在统计时间段内允许的最大请求数量
    "Limit": 1,
    // Http头 X-Rate-Limit 和 Retry-After 是否禁用
    // X-Rate-Limit: 为防止滥用,你应该考虑对您的 API 限流。 例如,您可以限制每个用户 10 分钟内最多调用 API 100 次。
    // Retry-After: 响应的 HTTP 报头指示所述用户代理应该多长时间使一个后续请求之前等待
    "DisableRateLimitHeaders": false,
    // QuotaExceededMessage - 当请求过载被截断时返回的消息
    "QuotaExceededMessage": "Customize Tips!",
    // HttpStatusCode - 当请求过载被截断时返回的http status
    "HttpStatusCode": 999,
    // ClientIdHeader - 用来识别客户端的请求头,默认是 ClientId
    "ClientIdHeader": "Test"
  },
  // 熔断的意思是停止将请求转发到下游服务。
  // 当下游服务已经出现故障的时候再请求也是无功而返,并且增加下游服务器和API网关的负担。
  // 这个功能是用的Pollly来实现的,我们只需要为路由做一些简单配置即可
  "QoSOptions": {
    // ExceptionsAllowedBeforeBreaking - 允许多少个异常请求
    "ExceptionsAllowedBeforeBreaking": 3,
    // DurationOfBreak - 熔断的时间,单位为秒
    "DurationOfBreak": 5,
    // TimeoutValue - 如果下游请求的处理时间超过多少则自如将请求设置为超时
    "TimeoutValue": 5000
  },
  // 本地配置
  // 可配置多个路由协议和规则,实现服务聚合、服务发现、认证、鉴权、限流、熔断、缓存、Header头传递等
  "GlobalConfiguration": {
    // 全局基础路径
    "BaseUrl": "http://127.0.0.1:8080"
  }
}

复制代码

  • Downstream:是下游服务配置
  • UpStream:是上游服务配置
  • Aggregates:服务聚合配置
  • ServiceName, LoadBalancer, UseServiceDiscovery:配置服务发现
  • AuthenticationOptions:配置服务认证
  • RouteClaimsRequirement:配置Claims鉴权
  • RateLimitOptions:为限流配置
  • FileCacheOptions:缓存配置
  • QosOptions:服务质量与熔断
  • DownstreamHeaderTransform:头信息转发

 

路由:

  ocelot的主要功能是接收传入的HTTP请求并将其转发到下游服务,不过目前只支持HTTP请求的形式(将来可能是任何传输机制,暗中窃喜,默默关注和等待吧)。ocelot将一个请求路由到另一个请求描述为路由,为了让任何请求在ocelot中工作,我们需要在配置中设置一个路由。

{
    "ReRoutes": [
    ]
}

  下面这个配置信息就是将用户的请求 /post/1 转发到 localhost/api/post/1

复制代码

{
    "DownstreamPathTemplate": "/api/post/{postId}",
    "DownstreamScheme": "https",
    "DownstreamHostAndPorts": [
            {
                "Host": "localhost",
                "Port": 80,
            }
        ],
    "UpstreamPathTemplate": "/post/{postId}",
    "UpstreamHttpMethod": [ "Get"]
}

复制代码

  • DownstreamPathTemplate:下游服务的路径模板,支持RESTful模板路径。
  • DownstreamScheme:下游服务协议,支持http和https。
  • DownstreamHostAndPorts:下游服务的地址和集合,用于定义要将请求转发到的任何下游服务的主机和端口,通常,这只包含一个条目,但有时您可能希望向下游服务加载负载均衡。
  • UpstreamPathTemplate: 上游也就是用户输入的请求Url模板,支持RESTful模板路径,或者设置一个空列表以允许其中任何一个方法。
  • UpstreamHttpMethod: 上游请求http方法,可使用数组。

 

捕获所有(通用模板):

  通用模板即所有请求全部转发,UpstreamPathTemplate与DownstreamPathTemplate设置为 “/{url}”

复制代码

{
    "DownstreamPathTemplate": "/{url}",
    "DownstreamScheme": "https",
    "DownstreamHostAndPorts": [
            {
                "Host": "localhost",
                "Port": 80,
            }
        ],
    "UpstreamPathTemplate": "/{url}",
    "UpstreamHttpMethod": [ "Get" ]
}

复制代码

  万能模板的优先级最低,只要有其它的路由模板,其它的路由模板则会优先生效。

 

上游Host:

  上游Host也是路由用来判断的条件之一,由客户端访问时的Host来进行区别。比如当a.jessetalk.cn/users/{userid}和b.jessetalk.cn/users/{userid}两个请求的时候都可以进行区别对待。

复制代码

{
    "DownstreamPathTemplate": "/",
    "DownstreamScheme": "https",
    "DownstreamHostAndPorts": [
            {
                "Host": "10.0.10.1",
                "Port": 80,
            }
        ],
    "UpstreamPathTemplate": "/",
    "UpstreamHttpMethod": [ "Get" ],
    "UpstreamHost": "a.jessetalk.cn"
}

复制代码

 

优先级:

  对多个产生冲突的路由设置优化级,可通过priority属性来定义我们希望路由与上游HttpRequest的匹配顺序。

复制代码

{
    "UpstreamPathTemplate": "/goods/{catchAll}"
    "Priority": 0
}
{
    "UpstreamPathTemplate": "/goods/delete"
    "Priority": 1
}

复制代码

  比如你有同样两个路由,当请求/goods/delete的时候,则下面那个会生效,也就是说Prority数值越大的会被优先匹配。

 

请求聚合:

  ocelot允许我们指定组成多个正常路由的聚合的重路由,并将它们的响应映射到一个下游对象中,通常情况下,当你有一个客户机向一个服务器发出多个请求时,它可能只是一个服务器,这个特性允许您使用ocelot开始实现前端类型体系结构到后端,还可以减少对后端服务节点的重复处理负载。

复制代码

{
    "ReRoutes": [
        {
            "DownstreamPathTemplate": "/",
            "UpstreamPathTemplate": "/laura",
            "UpstreamHttpMethod": [
                "Get"
            ],
            "DownstreamScheme": "http",
            "DownstreamHostAndPorts": [
                {
                    "Host": "localhost",
                    "Port": 51881
                }
            ],
            "Key": "Laura"
        },
        {
            "DownstreamPathTemplate": "/",
            "UpstreamPathTemplate": "/tom",
            "UpstreamHttpMethod": [
                "Get"
            ],
            "DownstreamScheme": "http",
            "DownstreamHostAndPorts": [
                {
                    "Host": "localhost",
                    "Port": 51882
                }
            ],
            "Key": "Tom"
        }
    ],
    "Aggregates": [
        {
            "ReRouteKeys": [
                "Tom",
                "Laura"
            ],
            "UpstreamPathTemplate": "/",
            "Aggregator": "FakeDefinedAggregator"
        }
    ]
}

复制代码

  在Startup中添加AddSingletonDefinedAggregator<FakeDefinedAggregator>来统一处理该路由聚合服务。

services.AddOcelot()
    .AddTransientDefinedAggregator<FakeDefinedAggregator>();

  而FakeDefinedAggregator需要继承于IDefinedAggregator,这样下游服务的统一处理将经过该Aggreage后返回到Response中。

复制代码

1 public class FakeDefinedAggregator : IDefinedAggregator
2 {
3     public Task<DownstreamResponse> Aggregate(List<DownstreamResponse> responses)
4     {
5        ...6     }
7 }

复制代码

  有了这个特性,您几乎可以做任何您想做的事情,因为下游响应包含内容、头和状态代码,请注意,如果httpclient在向聚合中的重新路由发出请求时抛出异常,那么您将不会得到它的下游响应,但会得到任何成功的响应,如果它确实引发了异常,则会记录此异常。

  如果我们设置  /tom 和 /laura 控制器下的返回值分别是  {“Age”: 19} 和 {“Age”: 25},那么我们请求端将收到如下一个Response信息

{"Tom":{"Age": 19},"Laura":{"Age": 25}}

  需要注意的是:

  • 聚合服务目前只支持返回json
  • 目前只支持Get方式请求下游服务
  • 任何下游的response header并会被丢弃
  • 如果下游服务返回404,聚合服务只是这个key的value为空,它不会返回404
  • 做一些像 GraphQL的处理对下游服务返回结果进行处理

  关于GraphQL的功能支持,Ocelot并无原生自带GraphQL动态API查询语句,如果需要集成GraphQL,Ocelot官方有自带示例:https://github.com/ThreeMammals/Ocelot/tree/develop/samples/OcelotGraphQL

 

路由负载均衡

  当下游服务有多个结点的时候,我们可以在DownstreamHostAndPorts中进行配置。

复制代码

{
    "DownstreamPathTemplate": "/api/posts/{postId}",
    "DownstreamScheme": "https",
    "DownstreamHostAndPorts": [
            {
                "Host": "10.0.1.10",
                "Port": 5000,
            },
            {
                "Host": "10.0.1.11",
                "Port": 5000,
            }
        ],
    "UpstreamPathTemplate": "/posts/{postId}",
    "LoadBalancer": "LeastConnection",
    "UpstreamHttpMethod": [ "Put", "Delete" ]
}

复制代码

  LoadBalancer将决定负载均衡的算法

  • LeastConnection – 将请求发往最空闲的那个服务器
  • RoundRobin – 轮流发送
  • NoLoadBalance – 总是发往第一个请求或者是服务发现

 

限流

  对请求进行限流可以防止下游服务器因为访问过载而崩溃,这个功能就是我们的张队添加进去的,Ocelot支持上游请求的速率限制,这样您的下游服务就不会过载。

复制代码

"RateLimitOptions": {
    "ClientWhitelist": [],
    "EnableRateLimiting": true,
    "Period": "1s",
    "PeriodTimespan": 1,
    "Limit": 1
}

复制代码

  • ClientWihteList 白名单
  • EnableRateLimiting 是否启用限流
  • Period 统计时间段:1s, 5m, 1h, 1d
  • PeroidTimeSpan 多少秒之后客户端可以重试
  • Limit 在统计时间段内允许的最大请求数量

  在 GlobalConfiguration下我们还可以进行以下配置

复制代码

"RateLimitOptions": {
  "DisableRateLimitHeaders": false,
  "QuotaExceededMessage": "Customize Tips!",
  "HttpStatusCode": 999,
  "ClientIdHeader" : "Test"
}

复制代码

  • Http头  X-Rate-Limit 和 Retry-After 是否禁用
  • QuotaExceedMessage 当请求过载被截断时返回的消息
  • HttpStatusCode 当请求过载被截断时返回的http status
  • ClientIdHeader 用来识别客户端的请求头,默认是 ClientId

 

服务质量和熔断

  熔断的意思是停止将请求转发到下游服务。当下游服务已经出现故障的时候再请求也是功而返,并且增加下游服务器和API网关的负担。这个功能是用的Pollly来实现的,我们只需要为路由做一些简单配置即可。关于Polly的使用,我会在下一个章节中介绍。

复制代码

"QoSOptions": {
    "ExceptionsAllowedBeforeBreaking":3,
    "DurationOfBreak":5,
    "TimeoutValue":5000
}

复制代码

  • ExceptionsAllowedBeforeBreaking 允许多少个异常请求
  • DurationOfBreak 熔断的时间,单位为秒
  • TimeoutValue 如果下游请求的处理时间超过多少则自如将请求设置为超时

 

缓存

  Ocelot支持一些非常基本的缓存功能,他是基于CacheManager实现的,当然,我们在使用的过程中,也需要安装CacheManager这个lib包,然后通过Ocelot Cache manager扩展方法来添加CacheManager实现。

复制代码

1 service.AddOcelot()
2     .AddCacheManager(x =>
3     {
4         x.WithDictionaryHandle();
5     })

复制代码

 

"FileCacheOptions": { "TtlSeconds": 15, "Region": "somename" }

  在这个例子中,ttl设置为15秒,那么缓存所存在的时长就只有15秒。当然,你也可以通过添加你自定义缓存接口来注入自定义缓存服务。

1 services.AddSingleton<IOcelotCache<CachedResponse>, MyCache>()

 

认证

  如果我们需要对下游API进行认证以及鉴权服务的,则首先Ocelot 网关这里需要添加认证服务。这和我们给一个单独的API或者ASP.NET Core Mvc添加认证服务没有什么区别。

复制代码

1 public void ConfigureServices(IServiceCollection services)
2 {
3     var authenticationProviderKey = "TestKey";
4 
5     services.AddAuthentication()
6         .AddJwtBearer(authenticationProviderKey, x =>
7         {
8         });
9 }

复制代码

   然后在ReRoutes的路由模板中的AuthenticationOptions进行配置,只需要我们的AuthenticationProviderKey一致即可。

复制代码

"ReRoutes": [{
        "DownstreamHostAndPorts": [
            {
                "Host": "localhost",
                "Port": 51876,
            }
        ],
        "DownstreamPathTemplate": "/",
        "UpstreamPathTemplate": "/",
        "UpstreamHttpMethod": ["Post"],
        "ReRouteIsCaseSensitive": false,
        "DownstreamScheme": "http",
        "AuthenticationOptions": {
            "AuthenticationProviderKey": "TestKey",
            "AllowedScopes": []
        }
    }]

复制代码

 

签权

  我们通过认证中的AllowedScopes 拿到 claims之后,如果要进行权限的鉴别需要添加以下配置。

"RouteClaimsRequirement": {
    "UserType": "registered"
}

  当前请求上下文的token中所带的claims如果没有 name=”UserType” 并且 value=”registered” 的话将无法访问下游服务。

 

一个简单的例子

  上面我们简单介绍了一下Ocelot的部分功能,要需完整功能介绍,可参考官方文档进行https://ocelot.readthedocs.io,接下来笔者做了一个简单的路由转发的示例,来演示一下Ocelot基于http/https协议的强大而又简单的功能。

  基于上面介绍的三个项目,我们只介绍了作为网关能使用到的功能,另外我们还需要一个上游作为请求客户端(当然,笔者更喜欢将客户端做成一个Console控制台,方便,快捷),一个下游作为服务端,项目名称任意。

  当下游服务端ASP.NET的默认模板被创建后,默认会创建一个ValueController,为了演示和获取当前路由转发的结果,我们只需要对其中一个接口稍作修改,设置默认启动端口为5000。

复制代码

1 // GET api/values
2 [HttpGet]
3 public ActionResult<IEnumerable<string>> Get()
4 {
5     return new[] { "WebServer", Request.GetDisplayUrl() };
6 }

复制代码

   而上游服务中,可以用HttpClient来模拟一个请求。

复制代码

1 using (var httpClient = new HttpClient())
2 {
3     // 此处访问的是网关的接口映射路径,而不是实际的接口URL路径
4     var response = httpClient.GetAsync(new Uri("http://127.0.0.1:8080/api/values")).Result;
5     Console.WriteLine("response: " + response);
6     Console.WriteLine("content: " + response.Content.ReadAsStringAsync().Result);
7 }

复制代码

  此处8080作为ApiGateway服务端,默认使用通用路由模板(上游和下游直接路由通用匹配{url}),代码不再贴出。启动8080网关和5000服务端,通过Console控制台直接访问8080所配置(映射)出来的公开地址(实际就是5000上的api/values),可看到如下的结果。

  如需查看更多的demo示例和源码,可参考笔者的源码https://github.com/steveleeCN87/doteasy.rpc/tree/master/src/doteasy.rpc.demo

 

转自:http://www.cnblogs.com/SteveLee/p/Ocelot_Api_http_and_https.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个在Ocelot使用AddDelegatingHandler处理超时异常的示例: 1. 在Ocelot配置文件中添加以下代码: ``` { "ReRoutes": [ { "DownstreamPathTemplate": "/api/{everything}", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5001 } ], "UpstreamPathTemplate": "/api/{everything}", "UpstreamHttpMethod": [ "Get" ], "Timeout": 5000, //设置超时时间 "DelegatingHandlers": [ "CustomDelegatingHandler" ] } ], "GlobalConfiguration": { "BaseUrl": "http://localhost:5000", "DelegatingHandlers": [ "CustomDelegatingHandler" ] } } ``` 上述代码中,我们在一个ReRoutes配置项中定义了一个超时时间为5秒的路由,并将CustomDelegatingHandler添加到DelegatingHandlers列表中。我们还在GlobalConfiguration中添加了CustomDelegatingHandler,以便在所有路由中使用。 2. 创建一个CustomDelegatingHandler类,代码如下: ``` using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Ocelot.Logging; public class CustomDelegatingHandler : DelegatingHandler { private readonly int _timeout; private readonly IOcelotLogger _logger; public CustomDelegatingHandler(int timeout, IOcelotLoggerFactory loggerFactory) { _timeout = timeout; _logger = loggerFactory.CreateLogger<CustomDelegatingHandler>(); } protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { using (var cts = new CancellationTokenSource()) { var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, cts.Token); linkedCts.CancelAfter(_timeout); try { return await base.SendAsync(request, linkedCts.Token); } catch (TaskCanceledException) when (!cancellationToken.IsCancellationRequested && !cts.IsCancellationRequested) { _logger.LogWarning($"Request timed out after {_timeout} ms: {request.Method} {request.RequestUri}"); return new HttpResponseMessage(System.Net.HttpStatusCode.RequestTimeout); } } } } ``` 上述代码中,我们定义了一个名为CustomDelegatingHandler的DelegatingHandler类,它接收一个超时时间参数timeout和一个IOcelotLoggerFactory对象来记录日志。在SendAsync方法中,我们使用CancellationTokenSource和linkedCts来设置请求的超时时间,并在请求超时时返回一个带有RequestTimeout状态代码的错误响应。我们还使用OcelotLogger记录了超时日志信息。 3. 在Startup.cs文件中通过以下代码注册CustomDelegatingHandler: ``` public void ConfigureServices(IServiceCollection services) { services.AddOcelot() .AddDelegatingHandler<CustomDelegatingHandler>(true); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseOcelot().Wait(); } ``` 上述代码中,我们使用AddDelegatingHandler方法将CustomDelegatingHandler注册到Ocelot中,并设置shouldThrow属性为true,以便在DelegatingHandler中发生异常时,抛出异常。 这样,我们就可以在Ocelot使用CustomDelegatingHandler处理超时异常了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值