环境:
- window10 x64
- vs2019 企业版 16.7.4
- asp.net core 3.1
- consul_1.8.4_windows_amd64.zip
- Consul 1.6.1.1
- Ocelot.Provider.Consul 16.0.1
关于Consul和Ocelot:
Consul
参照:c#:Consul初步体验
Ocelot
参照:c#:Ocelot初体验
实验代码下载:https://download.csdn.net/download/u010476739/13008990
一、实验概述和架构图
Consul
是用来做服务注册和发现的,我们写的WebApi
项目运行起来后需要向Consul
注册服务名称和访问地址。
Ocelot
是用来做网关的,所有客户端的请求都应该发送到Ocelot
,然后由Ocelot
内部转发(非http重定向)到具体的WebApi
项目。
Ocelot
集成Consul
后,我们开发的项目就只管向Consul
注册服务,而浏览器只管向Ocelot
发送请求,Ocelot
会自动向Consul
查询请求的服务地址,然后将请求内部转发到具体的WebApi
服务上。
下面是本地实现的架构图:
二、准备WebApi项目并向Consul注册
2.1 启动Consul
启动后,浏览器观察:http://localhost:8500/
2.2 准备WebApi
项目
我们先新建空白解决方案ocelot-consul-trial
,然后新建两个WebApi
项目:ocelot-consul-trial
和OrderApi
。
ocelot-consul-trial
是ocelot
网关项目,负责接收客户端请求。
OrderApi
是正常的WebApi
项目,启动时向Consul
注册。这个项目编译后,使用命令行参数指定端口启动两个实例。
新建后如下:
操作OrderApi
项目:
引入Consul
包:
<ItemGroup>
<PackageReference Include="Consul" Version="1.6.1.1" />
</ItemGroup>
修改Startup.cs
代码,加入向Consul
注册的代码:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
#region 向Consul注册服务
//获取命令行指定的参数( --urls="http://localhost:5001/")
var urls = Configuration["urls"];
var client = new ConsulClient(_ => _.Address = new Uri("http://localhost:8500"));
var httpCheck = new AgentServiceCheck()
{
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后注册
Interval = TimeSpan.FromSeconds(10),//间隔固定的时间访问一次
HTTP = $"{urls}/api/Health",//
Timeout = TimeSpan.FromSeconds(5)
};
var port = int.Parse(urls.Split(":")[2].Trim('/'));
AgentServiceRegistration registration = new AgentServiceRegistration()
{
Checks = new[] { httpCheck },
ID = Guid.NewGuid().ToString(),
Name = "OrderApi",
Address = "localhost",//注意:这里不要写成 http://localhost形式
Port = port
};
client.Agent.ServiceRegister(registration).Wait();
#endregion
}
添加健康检查控制器HealthController.cs
:
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace OrderApi.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class HealthController : ControllerBase
{
[HttpGet]
public string Get() => "ok";
}
}
添加测试api接口DemoController.cs
:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace OrderApi.Controllers
{
[ApiController]
[Route("api/[controller]/[action]")]
public class DemoController : ControllerBase
{
private readonly IConfiguration configuration;
public DemoController(IConfiguration configuration)
{
this.configuration = configuration;
}
public string GetHello() => "来自: " + configuration["urls"] + "的应答";
}
}
编译OrderApi
项目,并用如下命令启动两个实例:
.\OrderApi.exe --urls="http://localhost:5001"
.\OrderApi.exe --urls="http://localhost:5002"
此时观察Consul
管理页面:
三、准备网关项目
操作 ocelot-consul-trial
项目:
引入Ocelot.Provider.Consul
包:
<ItemGroup>
<PackageReference Include="Ocelot.Provider.Consul" Version="16.0.1" />
</ItemGroup>
添加ocelot.json
的配置文件:
{
"Routes": [
{
//GeteWay转发=>Downstream
"DownstreamPathTemplate": "/{url}", //服务地址--url变量
"DownstreamScheme": "http",
"UpstreamPathTemplate": "/order/{url}", //网关地址--url变量 冲突的还可以加权重Priority
"UpstreamHttpMethod": [ "Get", "Post" ],
"UseServiceDiscovery": true, //使用服务发现
"ServiceName": "OrderApi", //Consul服务名称
"LoadBalancerOptions": {
"Type": "RoundRobin" //轮询 //"LeastConnection":最少连接数服务器 "NoloadBalance":不负载均衡 "CookieStickySession":会话粘滞
}
}
],
"GlobalConfiguration": {
"ServiceDiscoveryProvider": {
"Host": "127.0.0.1",
"Port": 8500,
"Type": "Consul" //由Consul提供服务发现,每次请求去Consul
}
}
}
修改Program.cs
文件载入ocelot.json
配置文件:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace ocelot_consul_trial
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(conf =>
{
conf.AddJsonFile("ocelot.json", true, true);
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
修改Startup.cs
文件,启用 Ocelot
并去掉其他的功能:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
using Ocelot.Provider.Consul;
namespace ocelot_consul_trial
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddOcelot().AddConsul();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHttpsRedirection();
app.UseOcelot().Wait();
}
}
}
编译ocelot-consul-trial
项目并用如下命令启动:
.\ocelot-consul-trial.exe --urls="https://localhost:5000/"
四、测试整体效果
在浏览器中输入:https://localhost:5000/order/api/demo/gethello
,效果如下:
刷新网页,显示如下: