Ocelot之路由聚合
Ocelot之路由聚合
前言
通过上节介绍“Ocelot快速实践”后,了解了Ocelot网关,Ocelot网关还提供了路由集合功能。
例如:在获取订单记录时,也需要查看订单中对应的商品信息,这里的数据就来源于两个微服务:订单服务、商品服务。如果不使用聚合路由时,对于现实一个订单信息时,客户端需要调用两次服务请求,实际上会造成服务端额外的性能消耗。
如果配置了聚合路由,客户端只需要请求一次聚合路由,然后聚合路由会合并订单服务和商品服务的请求结果到一个对象中,并返回给客户端。使用Ocelot的此特性可以让你很容易的实现前后端分离的架构。
环境:
VS2022 +.NET5.0 + Ocelot17.0.0.0
1 Ocelot路由聚合介绍
Ocelot允许声明路由聚合,这样可以把多个正常的Routes打包并映射到一个对象来对客户端的请求进行响应。
步骤
1. 为每个Route设置一个Key属性:如:"Key": "Catalog"
2. 在ocelot.json中添加Aggregates节点,并指定RouteKeys中指定1中设置的Key值组成的数组,并设置UpstreamPathTemplate匹配上游用户请求;它的工作方式和正常的Route类似。
2 项目演示
接下来我们就来验证该功能的实现。
在上节“Ocelot快速实践”项目基础上进行改造,实现的目标是通过一个接口将多个接口的数据合并一起返回。项目机构如下:
2.1 修改接口服务
Step1 添加订单控制器“OrderController”用于取用户信息。代码如下:
namespace Yak.Ocelot.Api.Controllers [Produces("application/json")] [ApiController] [Route("api/[controller]/[action]")] public class UserController : ControllerBase { [HttpGet] public IActionResult GetSex(int id) { dynamic json; switch (id) { case 1: json = new { id = 1, name = "yak" }; break; case 2: json = new { id = 2, name = "zhang" }; break; default: json = new { id = 3, name = "li" }; break; } return new JsonResult(json); } [HttpGet] public IActionResult GetAge(int id) { dynamic json; switch (id) { case 1: json = new { id = 1, age = 23 }; break; case 2: json = new { id = 2, age = 24 }; break; default: json = new { id = 3, age = 25 }; break; } return new JsonResult(json); } } |
Step2 添加用户控制器“UserController”用于取用户信息。代码如下:
namespace order_api.Controllers [ApiController] public class OrderController : ControllerBase { private ILogger _logger; public OrderController(ILogger { _logger = logger; } [Route("api/Order/GetOrder")] [HttpGet] public IActionResult GetOrder(int id) { dynamic json; switch (id) { case 1: json = new { id = 1, order = "一箱牛奶" }; break; case 2: json = new { id = 2, order = "一台冰箱" }; break; default: json = new { id = 3, order = "一台洗衣机" }; break; } return new JsonResult(json); } } |
Step3 运行接口服务项目“Yak.Ocelot.Api”。
2.2 修改Ocelot网关配置
配置如下:
"Routes": [ { "DownstreamPathTemplate": "/WeatherForecast", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 6000 } ], "UpstreamPathTemplate": "/Weather", "UpstreamHttpMethod": [ "Get" ] }, { "DownstreamPathTemplate": "/api/User/GetSex", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 6000 } ], "UpstreamPathTemplate": "/Sex", "UpstreamHttpMethod": [ "Get" ], "Key": "Sex" } , { "DownstreamPathTemplate": "/api/User/GetAge", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 6000 } ], "UpstreamPathTemplate": "/Age", "UpstreamHttpMethod": [ "Get" ], "Key": "Age" } , { "DownstreamPathTemplate": "/api/Order/GetOrder", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 6000 } ], "UpstreamPathTemplate": "/Order", "UpstreamHttpMethod": [ "Get" ], "Key": "Order" } ], "Aggregates": [ { "RouteKeys": [ "Sex", "Age", "Order" ], "UpstreamPathTemplate": "/GetUserOrderInfo" } ], "GlobalConfiguration": { "BaseUrl": "https://localhost:5000" } |
2.3 验证路由聚合
Step1 运行网关项目“Yak.Ocelot.Gateway”。
Step2 通过网关访问聚合路由地址:“http://localhost:5000/GetUserOrderInfo?id=2”获取用户及他的订单。
2.4 接口异常
如接口异常,网关返回502代码,关闭接口服务,再访问网关。
2.5 自定义聚合
如果默认的聚合返回的结果数据结构不是我们想要的,想要修改怎么办?答案是使用自定义聚合
Step1 添加一个自动以聚合器MyAggregator, 必须实现IDefinedAggregator接口。这个聚合器的功能很简单,就是将两个聚合请求的结果,用逗号拼接起来返回
namespace Yak.Ocelot.Gateway public class MyAggregator : IDefinedAggregator { public MyAggregator() { } public async Task { List result.Add($"\"{Guid.NewGuid()}\":{{comment:\"我是自定义聚合器返回内容\"}}"); var merge = string.Join(";", result.ToArray()); List return await Task.FromResult(new DownstreamResponse(new StringContent(merge), HttpStatusCode.OK, headers, "some reason")); } } |
Step2 修改ocelot.json配置文件
"Aggregates": [ { "RouteKeys": [ "Sex", "Age", "Order" ], "UpstreamPathTemplate": "/GetUserOrderInfo", "Aggregator": "MyAggregator" } |
Step3 注册自定义聚合器,修改Startup文件。
public void ConfigureServices(IServiceCollection services) { services.AddOcelot().AddSingletonDefinedAggregator } |
Step4 运行结果:
3 总结
通过网关将各个接口的数据合并。
请求聚合需要为每个Route设置一个Key,并设置Aggregates节点指定需要的RouteKeys。
请求聚合支持自定义设置返回结果:实现IDefinedAggregator接口,并注册自定义聚合器
4 鸣谢
https://www.jianshu.com/p/585396dc885a
5 源码
https://github.com/yandaniugithub/NETCore