Ocelot简易教程(四)之请求聚合以及服务发现

Ocelot简易教程(四)之请求聚合以及服务发现

上篇文章给大家讲解了Ocelot的一些特性并对路由进行了详细的介绍,今天呢就大家一起来学习下Ocelot的请求聚合以及服务发现功能。希望能对大家有所帮助。

作者:依乐祝 原文地址:https://www.cnblogs.com/yilezhu/p/9695639.html

请求聚合

Ocelot允许你声明聚合路由,这样你可以把多个正常的ReRoutes打包并映射到一个对象来对客户端的请求进行响应。比如,你请求订单信息,订单中又包含商品信息,这里就设计到两个微服务,一个是商品服务,一个是订单服务。如果不运用聚合路由的话,对于一个订单信息,客户端可能需要请求两次服务端。实际上这会造成服务端额外的开销。这时候有了聚合路由后,你只需要请求一次聚合路由,然后聚合路由会合并订单跟商品的结果都一个对象中,并把这个对象响应给客户端。使用Ocelot的此特性可以让你很容易的实现前后端分离的架构。 为了实现Ocelot的请求功能,你需要在ocelot.json中进行如下的配置。这里我们指定了了两个正常的ReRoutes,然后给每个ReRoute设置一个Key属性。最后我们再Aggregates节点中的ReRouteKeys属性中加入我们刚刚指定的两个Key从而组成了两个ReRoutes的聚合。当然我们还需要设置UpstreamPathTemplate匹配上游的用户请求,它的工作方式与正常的ReRoute类似。

注意:不要把Aggregates中UpstreamPathTemplate设置的跟ReRoutes中的UpstreamPathTemplate设置成一样。

下面我们先上个实例例子先!演示代码已经同步更新Github上。有兴趣的朋友可以查看源码:https://github.com/yilezhu/OcelotDemo

在开始实例前先把我们的ocelot Nuget包升级到最新的12.0.0版本,当然你也可以不进行升级。这里需要注意一下,如果你升级到12.0.0的版本的话,那么你config.AddOcelot()的用法会发生改变,需要传入参数config.AddOcelot(hostingContext.HostingEnvironment)

1.为了演示的需要这里我们新增一个类库项目,分别新建两个类,一个是商品Good类,一个是订单Order类(这里只是为了演示的需要,所以代码很简陋)如下所示:

 public class Goods
    {
        public int Id { get; set; }
        public string Content { get; set; }
    }

public class Orders
    {
        public int Id { get; set; }
        public string Content { get; set; }
    }
  1. 接下来我们给OrderApi以及GoodApi分别新建一个控制器,并返回相应的实体。如下所示: //GoodApi项目中 [Route("api/[controller]")] [ApiController] public class GoodController : ControllerBase { // GET api/Good/5 [HttpGet("{id}")] public ActionResult<string> Get(int id) { var item = new Goods { Id = id, Content = $"{id}的关联的商品明细", }; return JsonConvert.SerializeObject(item); } } //OrderApi项目中 [Route("api/[controller]")] [ApiController] public class OrderController : ControllerBase { // GET api/Order/5 [HttpGet("{id}")] public ActionResult<string> Get(int id) { var item = new Orders { Id=id, Content=$"{id}的订单明细", }; return JsonConvert.SerializeObject(item); } }
  2. 接下来我们分别在ocelot.good.json以及ocelot.order.json中新增一个路由,并给出Keys.如下所示: 这里注意,跟上篇文章中的路由不同的是,这里多了一个Key属性。 //ocelot.good.json { "DownstreamPathTemplate": "/api/Good/{id}", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 1001 } ], "UpstreamPathTemplate": "/good/{id}", "UpstreamHttpMethod": [ "Get", "Post" ], "Key": "Good", "Priority": 2 } //ocelot.order.json { "DownstreamPathTemplate": "/api/Order/{id}", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 1002 } ], "UpstreamPathTemplate": "/order/{id}", "UpstreamHttpMethod": [ "Get", "Post" ], "Key": "Order", "Priority": 2 }
  3. 在ocelot.all.json中加入聚合配置,如下所示: "Aggregates": [ { "ReRouteKeys": [ "Good", "Order" ], "UpstreamPathTemplate": "/GetOrderDetail/{id}" } ] 注意:这里AggregatesReRoutes同级,ReRouteKeys中填写的数组就是上面步骤3中设置的Key属性对应的值。
  4. 我们分别运行起来三个项目,然后访问接口地址:http://localhost:1000/GetOrderDetail/1 会得到如下的聚合响应内容:

格式化后代码如下: { "Good":{ "Id":1, "Content":"1的关联的商品明细" }, "Order":{ "Id":1, "Content":"1的订单明细" } }

  1. 眼尖的朋友可能已经猜到了。聚合路由返回的内容就是json串。json串由ReRouteKeys组成,每个Key的内容就是具体下游响应的内容了!实例代码已经同步更新到Github上,地址:https://github.com/yilezhu/OcelotDemo Ocelot将始终使用聚合请求返回内容类型application/json。还有需要注意的是聚合请求不会返回404请求。如果两个下游都返回404状态码的话,这里聚合后的响应也不会返回404,只会返回空的json串,拿上面的实例,如果两个下游都返回404的话,那么他的响应代码类似下面这样: { "Good": , "Order": } 如果下游服务返回404,则聚合将仅为该下游服务返回任何内容。即使所有下游都返回404,它也不会将聚合响应更改为404。

服务发现

Ocelot允许您指定服务发现提供程序,并将使用它来查找Ocelot将请求转发到的下游服务的主机和端口。目前,这仅在GlobalConfiguration部分中受支持,这意味着相同的服务发现提供程序将用于为ReRoute级别指定ServiceName的所有ReRoutes。

Consul

在使用Consul前你首先要做的就是安装在Ocelot中提供Consul支持的NuGet包 Install-Package Ocelot.Provider.Consul 然后将下面的内容添加在ConfigureServices方法中

services.AddOcelot()//注入Ocelot服务
                    .AddConsul(); 

GlobalConfiguration中需要加入以下内容。如果您未指定主机和端口,则将使用Consul默认值。

"ServiceDiscoveryProvider": {
    "Host": "localhost",
    "Port": 8500,
    "Type": "Consul"
}

注意:如果你采用AddOcelot()这种方式来自动加载ocelot配置文件的方式,那么你需要新建一个ocelot.global.json文件,然后加入上面的配置:如下所示: { "GlobalConfiguration": { "ServiceDiscoveryProvider": { "Host": "localhost", "Port": 8500, "Type": "Consul" } } }

然后重新运行dotnet run命令会自动合并配置信息到Ocelot.json中,生成的对应内容如下: ​```C# "ServiceDiscoveryProvider": { "Host": "localhost", "Port": 8500, "Type": "Consul", "Token": null, "ConfigurationKey": null, "PollingInterval": 0 } 这个上篇文章中已经进行了相关的介绍。 为了告诉Ocelot ReRoute是为其主机和端口使用服务发现提供程序,您必须在下游请求时添加要使用的ServiceName和负载均衡器。目前,Ocelot可以使用RoundRobin和LeastConnection算法。如果未指定负载均衡器,则Ocelot将不会对请求进行负载均衡。

{
    "DownstreamPathTemplate": "/api/posts/{postId}",
    "DownstreamScheme": "https",
    "UpstreamPathTemplate": "/posts/{postId}",
    "UpstreamHttpMethod": [ "Put" ],
    "ServiceName": "product",
    "LoadBalancerOptions": {
        "Type": "LeastConnection"
    },
}

设置此项后,Ocelot将从服务发现提供程序中查找下游主机和端口,并跨任何可用服务进行负载平衡请求。

动态路由

作者的想法是在使用服务发现提供程序时启用动态路由。在此模式下,Ocelot将使用上游路径的第一个段来与服务发现提供程序一起查找下游服务。

例如,使用https://api.yilezhu.cn/product/products 等网址调用ocelot 。Ocelot将采用产品路径的第一部分product,并将其用作在Consul中查找服务的Key。如果consul返回一个服务,Ocelot将使用从consul返回的主机和端口以及剩余路径段组合后的Url来进行请求的响应。,如:http:// hostfromconsul:portfromconsul/products。Ocelot将正常向下游URL转发查询字符串。即query

要启用动态路由,您需要在配置中保留0个ReRoutes。目前您无法混合动态和配置ReRoutes。除此之外,您还需要指定上面概述的Service Discovery提供程序详细信息和下游http / https方案作为DownstreamScheme。

除此之外,您还可以设置RateLimitOptions,QoSOptions,LoadBalancerOptions和HttpHandlerOptions,DownstreamScheme(您可能希望在https上调用Ocelot,但可以通过http与私有服务进行通信),这些将应用于所有动态ReRoutes。

配置可能看起来像:

{
    "ReRoutes": [],
    "Aggregates": [],
    "GlobalConfiguration": {
        "RequestIdKey": null,
        "ServiceDiscoveryProvider": {
            "Host": "localhost",
            "Port": 8500,
            "Type": "Consul",
            "Token": null,
            "ConfigurationKey": null
        },
        "RateLimitOptions": {
            "ClientIdHeader": "ClientId",
            "QuotaExceededMessage": null,
            "RateLimitCounterPrefix": "ocelot",
            "DisableRateLimitHeaders": false,
            "HttpStatusCode": 429
        },
        "QoSOptions": {
            "ExceptionsAllowedBeforeBreaking": 0,
            "DurationOfBreak": 0,
            "TimeoutValue": 0
        },
        "BaseUrl": null,
            "LoadBalancerOptions": {
            "Type": "LeastConnection",
            "Key": null,
            "Expiry": 0
        },
        "DownstreamScheme": "http",
        "HttpHandlerOptions": {
            "AllowAutoRedirect": false,
            "UseCookieContainer": false,
            "UseTracing": false
        }
    }
}

Ocelot还允许您设置DynamicReRoutes,允许您为每个下游服务设置速率限制规则。如果您有一个产品和搜索服务,并且您希望对另一个进行速率限制,则此功能非常有用。这方面的一个例子如下。

{
    "DynamicReRoutes": [
        {
        "ServiceName": "product",
        "RateLimitRule": {
                "ClientWhitelist": [],
                "EnableRateLimiting": true,
                "Period": "1s",
                "PeriodTimespan": 1000.0,
                "Limit": 3
            }
        }
    ],
    "GlobalConfiguration": {
        "RequestIdKey": null,
        "ServiceDiscoveryProvider": {
            "Host": "localhost",
            "Port": 8523,
            "Type": "Consul"
        },
        "RateLimitOptions": {
            "ClientIdHeader": "ClientId",
            "QuotaExceededMessage": "",
            "RateLimitCounterPrefix": "",
            "DisableRateLimitHeaders": false,
            "HttpStatusCode": 428
        }
        "DownstreamScheme": "http",
    }
}

此配置意味着如果您在/product/上进入Ocelot请求,则动态路由将启动,并且ocelot将使用针对DynamicReRoutes部分中的产品服务的速率限制设置。

GitHub地址

https://github.com/yilezhu/OcelotDemo

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏熊二哥

快速入门系列--WCF--01基础概念

转眼微软的WCF已走过十个年头,它是微软通信框架的集大成者,将之前微软所有的通信框架进行了整合,提供了统一的应用方式。记得从自己最开始做MFC时,就使用过Nam...

233100
来自专栏安恒网络空间安全讲武堂

护网杯easy laravel ——Web菜鸡的详细复盘学习

复现让我发现了很多读wp以为懂了动手做的时候却想不通的漏掉的知识点(还是太菜orz),也让我对这道题解题逻辑更加理解。所以不要怂,就是干23333!

30030
来自专栏Seebug漏洞平台

CVE-2017-16943 Exim UAF漏洞分析--后续

作者:Hcamael@知道创宇404实验室 上一篇分析出来后,经过@orange的提点,得知了meh公布的PoC是需要特殊配置才能触发,所以我上一篇分析文章最后...

33060
来自专栏恰童鞋骚年

CMS项目实践学习总结

  这个暑假把ITCAST的2011年2月的.NET就业班的视频看了一遍,因为以前把免费的2010版和2011版的视频都看了一遍,所以这次选择了其中的几个部分作...

37450
来自专栏恰童鞋骚年

ASP.Net请求处理机制初步探索之旅 - Part 1 前奏

开篇:ASP.Net是一项动态网页开发技术,在历史发展的长河中WebForm曾一时成为了ASP.Net的代名词,而ASP.Net MVC的出现让这项技术更加唤发...

10820
来自专栏快乐八哥

ASP.NET中使用HttpWebRequest调用WCF

最近项目需要和第三网站进行数据交换,第三方网站基本都是RESTfull形式的API,但是也有的是Web Service,或者.NET里面的WCF。微软鼓励大家使...

45890
来自专栏Seebug漏洞平台

CVE-2017-16943 Exim UAF漏洞分析——后续

上一篇分析出来后,经过@orange的提点,得知了meh公布的PoC是需要特殊配置才能触发,所以我上一篇分析文章最后的结论应该改成,在默认配置情况下,meh提供...

43380
来自专栏进击的程序猿

raft 系列解读(3) 之 代码实现最小规则followercandidateleader规则RequestVote RPCAppendEntries RPC

首先,其实raft如果你不去看理论正确性的证明,光实现的话,只要按照raft里面给出的原则写代码就ok!如果代码写出来不正确,只能是你自己实现的问题。囧

11120
来自专栏jojo的技术小屋

原 web安全、XSS、CSRF、注入攻击

38230
来自专栏代码世界

Python中的logger和handler到底是个什么鬼

最近的任务经常涉及到日志的记录,特意去又学了一遍logging的记录方法。跟java一样,python的日志记录也是比较繁琐的一件事,在写一条记录之前,要写好多...

34090

扫码关注云+社区

领取腾讯云代金券