.Net Core with 微服务 - Ocelot 网关
上一次我们通过一张架构图(.Net Core with 微服务 - 架构图)来讲述了微服务的结构,分层等内容。从现在开始我们开始慢慢搭建一个最简单的微服务架构。这次我们先用几个简单的 web api 项目以及 ocelot 网关项目来演示下网关是如何配置,如何工作的。
Ocelot 网关
Ocelot 是使用 asp.net core 开发的一个 api 网关项目。它功能丰富,集成了路由、限流、缓存、聚合等功能。它使用 .net 编写,本质上就是一堆 asp.net core 的中间件,所以它天生对 .net 友好。这些中间件拦截外部的请求,根据路由配置转发到对应的内部服务上,再把内部的返回结果对外暴露。
搭建项目结构

新建一个解决方案,新建几个项目。
- api_gateway API网关
- hotel_base 酒店基本信息服务
- member_center 会员中心服务
- ordering 订单服务
安装 Ocelot
在API网关项目上使用nuget安装Ocelot的类库。Ocelot本质上就是一堆 asp.net Core 的 middleware。所以我们需要在UseOcelot扩展方法在注册这些中间件。
Install-Package Ocelot
public static void Main(string[] args)
{
new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
config
.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
.AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true)
.AddJsonFile("routes.json")
.AddEnvironmentVariables();
})
.ConfigureServices(s => {
s.AddOcelot();
})
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConsole();
})
.UseIISIntegration()
.Configure(app =>
{
app.UseOcelot().Wait();
})
.Build()
.Run();
}
}
在 main 函数内注册Ocelot的中间件,服务,使用AddJsonFile指定路由的配置文件。
路由
Ocelot最基本的功能就是反向代理。代理的配置通过一个json文件来配置。下面让我们来简单的演示下如何配置。
以下是通过网关代理访问酒店服务的酒店列表的配置示例。
{
//获取酒店列表
"UpstreamPathTemplate": "/api/hotel",
"UpstreamHttpMethod": [ "Get" ],
"DownstreamPathTemplate": "/hotel",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
//hotel service
"Host": "localhost",
"Port": 6003
}
]
}
配置主要是分为Upstream跟Downstream两部分。Upstream其实就是指代ocelot网关本身。Downstream代表真正的服务。
- UpstreamPathTemplate 网关匹配的路径
- UpstreamHttpMethod 网关匹配的请求方法
- DownstreamPathTemplate 服务匹配的路径
- DownstreamScheme 服务的Scheme,http、https
- DownstreamHostAndPorts 服务的主机地址跟端口
上面的配置描述的意思是:把对网关的/api/hotel的GET请求转发到主机http://localhost:6003/hotel接口上。

路由参数
Ocelot的path模板可以使用{param}模式来匹配参数,然后传递到下游服务器上。
{
//获取单个酒店
"UpstreamPathTemplate": "/api/hotel/{hotel_id}",
"UpstreamHttpMethod": [ "Get" ],
"DownstreamPathTemplate": "/hotel/{hotel_id}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
//hotel service
"Host": "localhost",
"Port": 6003
}
],
"Key": "hotel_base_info",
}
使用{hotel_id}匹配hotelId参数。
{
//获取酒店房间列表
"UpstreamPathTemplate": "/api/hotel_rooms/{hotel_id}",
"UpstreamHttpMethod": [ "Get" ],
"DownstreamPathTemplate": "/room/hotel_rooms/{hotel_id}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
//hotel service
"Host": "localhost",
"Port": 6003
}
],
"Key": "hotel_rooms"
}
使用{hotel_id}匹配hotelId参数。
{
//获取查询订单
"UpstreamPathTemplate": "/api/order/query?day={day}",
"UpstreamHttpMethod": [ "Get" ],
"DownstreamPathTemplate": "/order/get_orders?day={day}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
//order service
"Host": "localhost",
"Port": 6001
}
]
}
在QueryString上使用{day}匹配参数。
限流
Ocelot支持对请求的限流操作。
"RateLimitOptions": {
"EnableRateLimiting": true,
"Period": "1s",
"PeriodTimespan": 1,
"Limit": 1
}
在路由配置节点添加RateLimitOptions节点。
- EnableRateLimiting = true 开启限流
- Period = 1s 限流的时间区间为1s
- PeriodTimespan = 1 限流后重置时间
- Limit = 1 限制请求的数量
上面的配置的意思是1秒内限制一次请求,1秒后重置这个限制。
缓存
Ocelot可以对请求的响应值提供缓存服务。
//缓存5s
"FileCacheOptions": { "TtlSeconds": 5 }
在路由配置节点上配置FileCacheOptions字段,TtlSeconds代表需要缓存的时间,单位是秒。
聚合
上一回我们讲微服务架构的时候说到“聚合服务层”,我们说这一层的主要功能是对请求进行聚合适配跟裁剪。其实ocelot已经提供了简单的api聚合功能。如果聚合的需求比较简单,那么可以使用ocelot直接实现。
简单聚合
简单聚合可以通过配置把几个请求的聚合成一个请求,一次性返回几个请求的响应。响应通过json格式被包装返回。
"Aggregates": [
{
//聚合 查询酒店信息跟酒店房间列表
"RouteKeys": [
"hotel_base_info",
"hotel_rooms"
],
"UpstreamPathTemplate": "/api/hotel_detail/{hotel_id}"
},
]
RouteKeys 代表需要聚合的请求的键值。
使用代码聚合
上面我们直接通过配置实现了api之间聚合请求。这种聚合比较简单,会把聚合的几个请求的响应值原封不动的返回回来。有的时候我们需要对返回值做一些转换或者裁剪,比如同一个api我们对移动端的响应可能需要裁剪掉部分字段。这种需求在ocelot内我们可以使用代码来完成。
其实我们完全可以在代码里写业务,但是这种操作是绝对不推荐的。
这里我们演示下如何把获取酒店信息跟酒店房间列表的返回值进行裁剪,并返回一个新的响应。
public class HotelDetailInfoForMobileAggregator : IDefinedAggregator
{
public async Task<DownstreamResponse> Aggregate(List<HttpContext> responses)
{
dynamic hotelInfo = new ExpandoObject();
List<dynamic> rooms = new List<dynamic>();
foreach (var context in responses)
{
if ((context.Items["DownstreamRoute"] as dynamic).Key == "hotel_base_info")
{
var respContent = await context.Items.DownstreamResponse().Content.ReadAsStringAsync();
hotelInfo = JsonConvert.DeserializeObject<dynamic>(respContent);
}
if ((context.Items["DownstreamRoute"] as dynamic).Key == "hotel_rooms")
{
var respContent = await context.Items.DownstreamResponse().Content.ReadAsStringAsync();
rooms = JsonConvert.DeserializeObject<List<dynamic>>(respContent);
}
}
dynamic newResponse = new ExpandoObject();
newResponse.hotel = new {
hotelInfo.id,
hotelInfo.name
};
newResponse.rooms = rooms.Select(x => new {
x.id,
x.no
});
var stringContent = new StringContent(JsonConvert.SerializeObject(newResponse));
return new DownstreamResponse(
stringContent,
System.Net.HttpStatusCode.OK,
responses.SelectMany(x => x.Items.DownstreamResponse().Headers).ToList(),
"OK");
}
}
每一个聚合都需要继承IDefinedAggregator这个接口然后实现Aggregate方法。在这个方法内对每个请求的响应值进行裁剪,然后重新组合。
{
//聚合 查询酒店信息跟酒店房间列表 移动端 裁剪
"RouteKeys": [
"hotel_base_info",
"hotel_rooms"
],
"UpstreamPathTemplate": "/api/m/hotel_detail/{hotel_id}",
"Aggregator": "HotelDetailInfoForMobileAggregator"
}
在配置文件的Aggregates内添加一个配置节点在“Aggregator”字段上指定Aggregator的类名。
.ConfigureServices(s => {
s.AddOcelot()
.AddTransientDefinedAggregator<HotelDetailInfoForMobileAggregator>();
})
同时在ConfigureServices方法内配置HotelDetailInfoForMobileAggregator的依赖注入。
总结
本次我们通过几个最简单的web api项目,演示了如何使用 ocelot 网关进行反向代理,限流,聚合等常用功能。可以看到 ocelot 的配置使用还是比较简单的。因为是 .net 代码编写,所以对.net 开发者比较友好,我们可以直接使用 .net 代码来编写一些功能,比如直接使用代码来聚合请求的结果。
相关文章
NET Core with 微服务 - 什么是微服务
.Net Core with 微服务 - 架构图
演示代码
https://github.com/kklldog/myhotel_microservice
关注我的公众号一起玩转技术

.Net Core with 微服务 - Ocelot 网关的更多相关文章
- c# 微服务Ocelot网关服务发现
前面提到微服务方案,介绍了该东西,推荐一篇介绍博文https://www.cnblogs.com/jesse2013/p/net-core-apigateway-ocelot-docs.html 我要 ...
- .Net Core with 微服务 - Consul 注册中心
上一次我们介绍了 Ocelot 网关的基本用法.这次我们开始介绍服务注册发现组件 Consul 的简单使用方法. 服务注册发现 首先先让我们回顾下服务注册发现的概念. 在实施微服务之后,我们的调用都变 ...
- .Net Core with 微服务 - Seq 日志聚合
上一次我们介绍并演示了如果使用 Consul 做为我们微服务的注册中心,来实现服务的注册与发现.那么本次我们讲会演示如何做日志聚合.日志聚合比较常用的有 ELK 等,但是这次我想要介绍的是一款比较小众 ...
- .Net Core with 微服务 - Elastic APM
上一次我们介绍了Seq日志聚合组件.这次要给大家介绍的是Elastic APM ,一款应用程序性能监控组件.APM 监控围绕对应用.服务.容器的健康监控,对接口的调用链.性能进行监控.在我们实施微服务 ...
- .Net Core with 微服务 - Consul 配置中心
上一次我们介绍了Elastic APM组件.这一次我们继续介绍微服务相关组件配置中心的使用方法.本来打算介绍下携程开源的重型配置中心框架 apollo 但是体系实在是太过于庞大,还是让我爱不起来.因为 ...
- .Net Core with 微服务 - Polly 服务降级熔断
在我们实施微服务之后,服务间的调用变的异常频繁.多个服务之间可能是互相依赖的关系.某个服务出现故障或者是服务间的网络出现故障都会造成服务调用的失败,进而影响到某个业务服务处理失败.某一个服务调用失败轻 ...
- .Net Core with 微服务 - 分布式事务 - 2PC、3PC
最近比较忙,好久没更新了.这次我们来聊一聊分布式事务. 在微服务体系下,我们的应用被分割成多个服务,每个服务都配置一个数据库.如果我们的服务划分的不够完美,那么为了完成业务会出现非常多的跨库事务.即使 ...
- .Net Core with 微服务 - 分布式事务 - TCC
上一次我们讲解了分布式事务的 2PC.3PC .那么这次我们来理一下 TCC 事务.本次还是讲解 TCC 的原理跟 .NET 其实没有关系. TCC Try 准备阶段,尝试执行业务 Confirm 完 ...
- .Net Core with 微服务 - 分布式事务 - 可靠消息最终一致性
前面我们讲了分布式事务的2PC.3PC , TCC 的原理.这些事务其实都在尽力的模拟数据库的事务,我们可以简单的认为他们是一个同步行的事务.特别是 2PC,3PC 他们完全利用数据库的事务能力,在一 ...
随机推荐
- 通过钉钉网页上的js学习xss打cookie
做完了一个项目,然后没啥事做,无意看到了一个钉钉的外部链接: 题外话1: 查看源码,复制其中的代码: try { var search = location.search; if (search &a ...
- Python中面向对象和类
目录 面向对象 类的定义 类的访问 类的属性和方法 继承和多态 面向对象 Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的. 面向对象: 类(C ...
- 票据传递攻击(Pass the Ticket,PtT)
目录 黄金票据 生成票据并导入 查看票据 验证是否成功 黄金票据和白银票据的不同 票据传递攻击(PtT)是一种使用Kerberos票据代替明文密码或NTLM哈希的方法.PtT最常见的用途可能是使用黄金 ...
- MS06-040漏洞研究(上)【转载】
课程简介 我在之前的课程中讨论过W32Dasm这款软件中的漏洞分析与利用的方法,由于使用该软件的人群毕竟是小众群体,因此该漏洞的危害相对来说还是比较小的.但是如果漏洞出现在Windows系统中,那么情 ...
- Intel汇编语言程序设计学习-第五章 过程-下
5.3.3 库测试程序 测试程序#1:整数I/O 该测试程序把输出文本的颜色改为蓝底黄字,然后以十六进制数显示七个数组的内容,最后提示用户输入一个有符号整数,再分别以十进制.十六进制和二进制格式重复 ...
- jquery里面.length和.size()有什么区别
区别: 1.针对标签对象元素,比如数html页面有多少个段落元素<p></p>,那么此时的$("p").size()==$("p").l ...
- 【vue-01】快速入门
什么是vue vue是渐进式的JavaScript框架 什么是渐进式? 你可以在原有大系统的上面,把一两个组件改用vue实现,:也可以整个项目用vue全家桶开发. vue是一个轻量级的MVVM ...
- ConcurrentHashMap源码解读二
接下来就讲解put里面的三个方法,分别是 1.数组初始化方法initTable() 2.线程协助扩容方法helpTransfer() 3.计数方法addCount() 首先是数组初始化,再将源码之前, ...
- 查看.class文件的工具
1.JDK 提供的 javap -c javap -c test.class 2.将test.class用idea打开.
- 【哲学角度看软件测试】要想软件“一想之美”,UI 测试少不了
摘要:软件测试的最高层次需求是:UI测试,也就是这个软件"长得好不好看". 为了让读者更好地理解测试,我们从最基础的概念开始介绍.以一个软件的"轮回"为例,下图 ...