
網關介紹
網關其實就是將我們寫好的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=https://www.cnblogs.com/meowv/archive/2020/09/28/ApiA"
curl -X POST "https://localhost:44335/ApiB" -H "Content-Type: multipart/form-data" -F "value=https://www.cnblogs.com/meowv/archive/2020/09/28/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=https://www.cnblogs.com/meowv/archive/2020/09/28/ApiA"
curl -X PUT "https://localhost:44335/ApiB/12345" -H "Content-Type: multipart/form-data" -F "value=https://www.cnblogs.com/meowv/archive/2020/09/28/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的功能遠不止于此,它非常強大,還可以實作請求聚合、服務發現、認證、鑒權、限流熔斷、并內置了負載均衡器,而且這些功能都是只需要簡單的配置即可完成,就不一一描述了,如有實際開發需求和問題,可以查看官方檔案和示例,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/134794.html
標籤:.NET技术
