.NET Core 下的 API 网关

网关介绍
网关其实就是将我们写好的API全部放在一个统一的地址暴露在公网,提供访问的一个入口。在 .NET Core下可以使用Ocelot来帮助我们很方便的接入API 网关。与之类似的库还有ProxyKit,微软也发布了一个反向代理的库YARP。
关于网关的介绍不多说了,网上文章也挺多的,这些都是不错的选择,听说后期Ocelot将会使用YARP来重写。本篇主要实践一下在.NET Core环境下使用Ocelot。
- Ocelot官网:https://threemammals.com/ocelot
- Ocelot文档:https://ocelot.readthedocs.io
- GitHub:https://github.com/ThreeMammals/Ocelot
- Ocelot资源汇总:https://www.cnblogs.com/shanyou/p/10363360.html
接入使用
接口示例
先创建几个项目用于测试,创建两个默认的API项目,Api_A和Api_B,在创建一个网关项目Api_Gateway,网关项目可以选择空的模板。
现在分别在Api_A和Api_B中写几个api,将默认的WeatherForecastController中返回模型WeatherForecast添加一个字段Source,用于区分是哪个API返回的数据。
using System;
namespace Api_A
{
public class WeatherForecast
{
public string Source { get; set; } = "Api_A";
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string Summary { get; set; }
}
}
using System;
namespace Api_B
{
public class WeatherForecast
{
public string Source { get; set; } = "Api_B";
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string Summary { get; set; }
}
}
直接使用WeatherForecastController默认方法,在路由中添加api前缀。
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Api_A.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
}).ToArray();
}
}
}
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Api_B.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
}).ToArray();
}
}
}
再分别在Api_A和Api_B中添加两个控制器:ApiAController、ApiBController,然后加上几个简单的restful api。
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
namespace Api_A.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ApiAController : ControllerBase
{
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
[HttpGet("{id}")]
public string Get(int id)
{
return $"Get:{id}";
}
[HttpPost]
public string Post([FromForm] string value)
{
return $"Post:{value}";
}
[HttpPut("{id}")]
public string Put(int id, [FromForm] string value)
{
return $"Put:{id}:{value}";
}
[HttpDelete("{id}")]
public string Delete(int id)
{
return $"Delete:{id}";
}
}
}
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
namespace Api_B.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ApiBController : ControllerBase
{
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
[HttpGet("{id}")]
public string Get(int id)
{
return $"Get:{id}";
}
[HttpPost]
public string Post([FromForm] string value)
{
return $"Post:{value}";
}
[HttpPut("{id}")]
public string Put(int id, [FromForm] string value)
{
return $"Put:{id}:{value}";
}
[HttpDelete("{id}")]
public string Delete(int id)
{
return $"Delete:{id}";
}
}
}


方便查看接口,这里添加一下swagger组件,这样我们Api_A和Api_B项目分别就有了6个接口。
接着打包docker镜像,放在docker中运行这两个api项目。这一步可以用任何你熟悉的方式,run起来即可。
docker build -t api_a:dev -f ./Api_A/Dockerfile .
docker build -t api_b:dev -f ./Api_B/Dockerfile .
build成功后,指定两个端口运行api项目。
docker run -d -p 5050:80 --name api_a api_a:dev
docker run -d -p 5051:80 --name api_b api_b:dev
Api_A指定了5050端口,通过 http://localhost:5050/swagger打开可以看到swagger文档界面,Api_B指定了5051端口,通过 http://localhost:5051/swagger打开可以看到swagger文档界面,这样就大功告成了,接下来才是重点将两个api项目配置到Api_Gateway网关项目中。
配置网关
在网关项目Api_Gateway中都添加Ocelot组件包。
Install-Package Ocelot
Ocelot中最关键的就是配置路由信息,新建一个ocelot.json配置文件,将我们的两个API接口匹配规则放进去。
{
"Routes": [
//ApiA
{
"DownstreamPathTemplate": "/api/WeatherForecast",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5050
}
],
"UpstreamPathTemplate": "/ApiA/WeatherForecast",
"UpstreamHttpMethod": [ "Get" ]
},
{
"DownstreamPathTemplate": "/api/ApiA",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5050
}
],
"UpstreamPathTemplate": "/ApiA",
"UpstreamHttpMethod": [ "Get", "POST" ]
},
{
"DownstreamPathTemplate": "/api/ApiA/{id}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5050
}
],
"UpstreamPathTemplate": "/ApiA/{id}",
"UpstreamHttpMethod": [ "Get", "Put", "Delete" ]
},
//ApiB
{
"DownstreamPathTemplate": "/api/WeatherForecast",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5051
}
],
"UpstreamPathTemplate": "/ApiB/WeatherForecast",
"UpstreamHttpMethod": [ "Get" ]
},
{
"DownstreamPathTemplate": "/api/ApiB",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5051
}
],
"UpstreamPathTemplate": "/ApiB",
"UpstreamHttpMethod": [ "Get", "POST" ]
},
{
"DownstreamPathTemplate": "/api/ApiB/{id}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5051
}
],
"UpstreamPathTemplate": "/ApiB/{id}",
"UpstreamHttpMethod": [ "Get", "Put", "Delete" ]
}
],
"GlobalConfiguration": {
"BaseUrl": "https://localhost:44335"
}
}
关于配置文件中的各项具体含义,可以参考官方文档中的介绍。主要就是将DownstreamPathTemplate模板内容转换为UpstreamPathTemplate模板内容进行接口的访问,同时可以指定HTTP请求的方式等等。GlobalConfiguration中的BaseUrl为我们暴漏出去的网关地址。
设置好ocelot.json后,需要在代码中使用它,在Program.cs中添加配置文件。
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
namespace Api_Gateway
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, config) =>
{
config.AddJsonFile("ocelot.json", optional: false, reloadOnChange: true);
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
在Startup.cs中使用Ocelot。
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
namespace Api_Gateway
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddOcelot();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
app.UseOcelot().Wait();
}
}
}
完成以上操作后,我们试着去调用接口看看能否正确获取预期数据。
curl -X GET "https://localhost:44335/ApiA"
curl -X GET "https://localhost:44335/ApiB"
curl -X POST "https://localhost:44335/ApiA" -H "Content-Type: multipart/form-data" -F "value=ApiA"
curl -X POST "https://localhost:44335/ApiB" -H "Content-Type: multipart/form-data" -F "value=ApiB"
curl -X GET "https://localhost:44335/ApiA/12345"
curl -X GET "https://localhost:44335/ApiB/12345"
curl -X PUT "https://localhost:44335/ApiA/12345" -H "Content-Type: multipart/form-data" -F "value=ApiA"
curl -X PUT "https://localhost:44335/ApiB/12345" -H "Content-Type: multipart/form-data" -F "value=ApiB"
curl -X DELETE "https://localhost:44335/ApiA/12345"
curl -X DELETE "https://localhost:44335/ApiB/12345"
curl -X GET "https://localhost:44335/ApiA/WeatherForecast"
curl -X GET "https://localhost:44335/ApiB/WeatherForecast"

可以看到,两个项目中的接口全部可以通过网关项目暴露的地址进行中转,是不是很方便?
本篇只是简单的应用,对于Ocelot的功能远不止于此,它非常强大,还可以实现请求聚合、服务发现、认证、鉴权、限流熔断、并内置了负载均衡器,而且这些功能都是只需要简单的配置即可完成。就不一一描述了,如有实际开发需求和问题,可以查看官方文档和示例。
.NET Core 下的 API 网关的更多相关文章
- .NET Core 微服务—API网关(Ocelot) 教程 [二]
上篇文章(.NET Core 微服务—API网关(Ocelot) 教程 [一])介绍了Ocelot 的相关介绍. 接下来就一起来看如何使用,让它运行起来. 环境准备 为了验证Ocelot 网关效果,我 ...
- .NET Core 微服务—API网关(Ocelot) 教程 [三]
前言: 前一篇文章<.NET Core 微服务—API网关(Ocelot) 教程 [二]>已经让Ocelot和目录api(Api.Catalog).订单api(Api.Ordering)通 ...
- .net core Ocelot实现API网关并部署在docker中
基于Ocelot(http://ocelot.readthedocs.io)搭建的API网关demo 软件以及系统版本: Asp.Net Core 2.2 Ocelot 13.5.0 CentOS ...
- .NET Core 微服务—API网关(Ocelot) 教程 [一]
前言: 最近在关注微服务,在 eShop On Containers 项目中存在一个API网关项目,引起想深入了解下它的兴趣. 一.API网关是什么 API网关是微服务架构中的唯一入口,它提供一个单独 ...
- 微服务架构下的API网关
顾名思义,是出现在系统边界上的一个面向API的.串行集中式的强管控服务,这里的边界是企业IT系统的边界,主要起到隔离外部访问与内部系统的作用.在微服务概念的流行之前,API网关的实体就已经诞生了,例如 ...
- .net core下,Ocelot网关与Spring Cloud Gateway网关的对比测试
有感于 myzony 发布的 针对 Ocelot 网关的性能测试 ,并且公司下一步也需要对.net和java的应用做一定的整合,于是对Ocelot网关.Spring Cloud Gateway网关做个 ...
- .net core 下Web API 技术栈
API文档工具:swagger https://www.cnblogs.com/suxinlcq/p/6757556.html https://www.cnblogs.com/danvic712/p/ ...
- .NET Core 微服务—API网关(Ocelot) 教程 [四]
前言: 上一篇 介绍了Ocelot网关和认证服务的结合使用,本篇继续介绍Ocelot相关请求聚合和Ocelot限流 一.请求聚合 Ocelot允许声明聚合路由,这样可以把多个正常的Routes打包并映 ...
- .net core Ocelot Consul 实现API网关 服务注册 服务发现 负载均衡
大神张善友 分享过一篇 <.NET Core 在腾讯财付通的企业级应用开发实践>里面就是用.net core 和 Ocelot搭建的可扩展的高性能Api网关. Ocelot(http:// ...
随机推荐
- Centos7 安装python3 pip3
Centos7 安装python3 pip3 安装python3.6 安装 python36 yum install python36 -y 查看版本 安装完成,查看一下python版本是否正 ...
- C语言讲义——结构体struct
结构体是一种变量类型,可以包含多个变量(变量类型不必相同). 结构体的关键字是struct也是一种值类型. 例:设计一个表示"书本"的结构体: structBook { chari ...
- C语言讲义——快速排序
快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序 它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod) 基本思想: 1.先从数列中取出一个数作 ...
- Cisco交换机常见配置
-------查看当前系统基础信息-------- sh version //查看当前IOS版本. sh running-config //查看当前系统中运行的配置信息 -------清除当前系统配置 ...
- JZOJ2020年8月11日提高组T2 宝石
JZOJ2020年8月11日提高组T2 宝石 题目 Description 见上帝动了恻隐之心,天后也想显示一下慈悲之怀,随即从口袋中取出一块魔术方巾,让身边的美神维纳斯拿到后堂的屏风上去试试,屏风是 ...
- 推荐系统实践 0x0b 矩阵分解
前言 推荐系统实践那本书基本上就更新到上一篇了,之后的内容会把各个算法拿来当专题进行讲解.在这一篇,我们将会介绍矩阵分解这一方法.一般来说,协同过滤算法(基于用户.基于物品)会有一个比较严重的问题,那 ...
- Python爬虫实战案例:取喜马拉雅音频数据详解
前言 喜马拉雅是专业的音频分享平台,汇集了有声小说,有声读物,有声书,FM电台,儿童睡前故事,相声小品,鬼故事等数亿条音频,我最喜欢听民间故事和德云社相声集,你呢? 今天带大家爬取喜马拉雅音频数据,一 ...
- .Net Core JWT 动态设置接口与权限
通过上一篇.Net Core官方的 JWT 授权验证学习到了JWT的授权.可以发现一个问题,就是如果每个接口可以使用的角色都是写死的,这样如果有所修改会非常麻烦,虽然用policy可以一定程度上缓解, ...
- 【手把手学习flutter】Flutter打Android包的基本配置和包体积优化策略
[手把手学习flutter]Flutter打Android包的基本配置和包体积优化策略 关注「松宝写代码」,回复"加群" 加入我们一起学习,天天向上 前言 因为最近参加2020FE ...
- PyQt(Python+Qt)学习随笔:model/view架构中的排序和代理模型QSortFilterProxyModel
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 一.概述 在Model/View体系架构中,有两种方法可以进行排序:选择哪种方法取决于底层模型. 如 ...