.NET Core 下的 API 網(wǎng)關(guān)

網(wǎng)關(guān)介紹
網(wǎng)關(guān)其實就是將我們寫好的API全部放在一個統(tǒng)一的地址暴露在公網(wǎng),提供訪問的一個入口。在 .NET Core下可以使用Ocelot來幫助我們很方便的接入API 網(wǎng)關(guān)。與之類似的庫還有ProxyKit,微軟也發(fā)布了一個反向代理的庫YARP。
關(guān)于網(wǎng)關(guān)的介紹不多說了,網(wǎng)上文章也挺多的,這些都是不錯的選擇,聽說后期Ocelot將會使用YARP來重寫。本篇主要實踐一下在.NET Core環(huán)境下使用Ocelot。
Ocelot官網(wǎng):https://threemammals.com/ocelot Ocelot文檔:https://ocelot.readthedocs.io GitHub:https://github.com/ThreeMammals/Ocelot Ocelot資源匯總:https://www.cnblogs.com/shanyou/p/10363360.html
接入使用
接口示例
先創(chuàng)建幾個項目用于測試,創(chuàng)建兩個默認(rèn)的API項目,Api_A和Api_B,在創(chuàng)建一個網(wǎng)關(guān)項目Api_Gateway,網(wǎng)關(guān)項目可以選擇空的模板。
現(xiàn)在分別在Api_A和Api_B中寫幾個api,將默認(rèn)的WeatherForecastController中返回模型WeatherForecast添加一個字段Source,用于區(qū)分是哪個API返回的數(shù)據(jù)。
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默認(rèn)方法,在路由中添加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?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?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網(wǎng)關(guān)項目中。
配置網(wǎng)關(guān)
在網(wǎng)關(guān)項目Api_Gateway中都添加Ocelot組件包。
Install-Package Ocelot
Ocelot中最關(guān)鍵的就是配置路由信息,新建一個ocelot.json配置文件,將我們的兩個API接口匹配規(guī)則放進(jìn)去。
{
??"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"
??}
}
關(guān)于配置文件中的各項具體含義,可以參考官方文檔中的介紹。主要就是將DownstreamPathTemplate模板內(nèi)容轉(zhuǎn)換為UpstreamPathTemplate模板內(nèi)容進(jìn)行接口的訪問,同時可以指定HTTP請求的方式等等。GlobalConfiguration中的BaseUrl為我們暴漏出去的網(wǎng)關(guān)地址。
設(shè)置好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.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();
????????}
????}
}
完成以上操作后,我們試著去調(diào)用接口看看能否正確獲取預(yù)期數(shù)據(jù)。
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"

可以看到,兩個項目中的接口全部可以通過網(wǎng)關(guān)項目暴露的地址進(jìn)行中轉(zhuǎn),是不是很方便?
本篇只是簡單的應(yīng)用,對于Ocelot的功能遠(yuǎn)不止于此,它非常強大,還可以實現(xiàn)請求聚合、服務(wù)發(fā)現(xiàn)、認(rèn)證、鑒權(quán)、限流熔斷、并內(nèi)置了負(fù)載均衡器,而且這些功能都是只需要簡單的配置即可完成。就不一一描述了,如有實際開發(fā)需求和問題,可以查看官方文檔和示例。


90后中國程序員“黑吃黑”博彩網(wǎng)站,半年獲利256萬,判刑11年半

PanDownload復(fù)活了,60MB/s,目前已開源!
