The gateway is introduced
In fact, the gateway is to put all our written API in a unified address exposed to the public network, providing access to an entrance. Ocelot can be used with.NET Core to facilitate API gateway access. Similar libraries include ProxyKit, and Microsoft has released a reverse proxy library called YARP.
There is not much to say about the gateway, and there are a lot of articles online. These are good choices. I heard that Ocelot will use YARP to rewrite the gateway in the future. This article mainly practices in. Use Ocelot in NET Core.
- Ocelot website: threemammals.com/ocelot
- Ocelot documentation: Ocelot. Readthedocs. IO
- GitHub:github.com/ThreeMammal…
- Ocelot resource summary: www.cnblogs.com/shanyou/p/1…
Access to the use of
Interface sample
Create two default API projects, Api_A and Api_B, and then create a gateway project, Api_Gateway, which can choose an empty template.
Now in Api_A and Api_B wrote several API, will return to model in the default WeatherForecastController WeatherForecast add a field Source, which is used to distinguish the data returned by the 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; }}}Copy the code
Use WeatherForecastController default method, directly added to the routing API prefix.
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(); }}}Copy the code
Add two controllers, ApiAController and ApiBController, respectively to Api_A and Api_B, and add some simple restful apis.
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}"; }}}Copy the code
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}"; }}}Copy the code
Add swagger component here so that we have 6 interfaces for Api_A and Api_B projects respectively.
Then package the Docker image and run the two API projects in docker. This step can be done in any way you’re familiar with, just run.
docker build -t api_a:dev -f ./Api_A/Dockerfile .
docker build -t api_b:dev -f ./Api_B/Dockerfile .
Copy the code
After a successful build, specify two ports to run the API project.
docker run -d -p 5050:80 --name api_a api_a:dev
docker run -d -p 5051:80 --name api_b api_b:dev
Copy the code
Api_A specifies the port 5050, via http://localhost:5050/swagger to open the can see swagger document interface, Api_B specifies the port 5051, Through http://localhost:5051/swagger to open the can see swagger document interface, accomplished this, next is the key to two API project configuration to the Api_Gateway gateway project.
Configure the gateway
Add the Ocelot component package to the gateway project Api_Gateway.
Install-Package Ocelot
Copy the code
The most important thing in Ocelot is to configure the routing information. Create an Ocelot. Json configuration file and put our two API matching rules in it.
{
"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"}}Copy the code
For details about each item in the configuration file, see the official documents. This is done by converting DownstreamPathTemplate content to UpstreamPathTemplate content for interface access, specifying HTTP requests, and so on. BaseUrl in GlobalConfiguration is the leaked gateway address.
Once you have set up ocelot. Json, you need to use it in your code, adding configuration files to 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>(); }); }}Copy the code
Use Ocelot in Startup.cs.
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(); }}}Copy the code
Once that’s done, we try calling the interface to see if we can get the expected data correctly.
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"
Copy the code
As you can see, the interfaces in both projects can all be relayed through the address exposed by the gateway project. Isn’t it convenient?
This is just a simple application, but Ocelot does a lot more than that. It’s very powerful. It can do request aggregation, service discovery, authentication, authentication, current limiting circuit breaker, and load balancer, all of which require simple configuration. I won’t describe it in detail, but if you have actual development requirements and problems, you can check out the official documentation and examples.