网关介绍

网关其实就是将我们写好的API全部放在一个统一的地址暴露在公网,提供访问的一个入口。在 .NET Core下可以使用Ocelot来帮助我们很方便的接入API 网关。与之类似的库还有ProxyKit,微软也发布了一个反向代理的库YARP

关于网关的介绍不多说了,网上文章也挺多的,这些都是不错的选择,听说后期Ocelot将会使用YARP来重写。本篇主要实践一下在.NET Core环境下使用Ocelot

接入使用

接口示例

先创建几个项目用于测试,创建两个默认的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的功能远不止于此,它非常强大,还可以实现请求聚合、服务发现、认证、鉴权、限流熔断、并内置了负载均衡器,而且这些功能都是只需要简单的配置即可完成。就不一一描述了,如有实际开发需求和问题,可以查看官方文档和示例。

最新文章

  1. 增强学习(三)----- MDP的动态规划解法
  2. 浅玩JavaScript的数据类型判断
  3. 严重: Error configuring application listener of class org.springframework.web.context.ContextLoaderLis
  4. PHP 监控服务器动态
  5. 解决64位Windows2003程序字体很小的问题
  6. excel中将字符转换为数值
  7. BizTalk动手实验(九)业务规则引擎使用
  8. mybatis动态sql中的trim标签的使用(转)
  9. android学习日记03--常用控件Dialog
  10. hdu1556 Color the ball
  11. android项目 之 记事本(12) ----- 图片的等比例缩放及给图片加入边框
  12. SpringMVC结合ajaxfileupload文件无刷新上传
  13. MySql数据库第一天
  14. Netty的并发编程实践2:volatile的正确使用
  15. CSS的使用方法
  16. BZOJ-3208|记忆化搜索-花神的秒题计划Ⅰ
  17. Ubuntu忘记超级用户root密码,重新设置密码
  18. mysql可以远程连接的配置
  19. [UE4]InterpToMovement
  20. Java源码阅读(不断补充)

热门文章

  1. yii2.0验证码的两种实现方式
  2. [python学习手册-笔记]003.数值类型
  3. Problem D. Country Meow 题解(三分套三分套三分)
  4. Mac 安装Homebrew慢的问题解决
  5. Java集合【6】-- Collection和Collections的区别
  6. 那么多人学习C++,学习它有什么好处?学完以后能从事哪些岗位?
  7. 记录一下超大list引起oom
  8. Tiops评测
  9. Spring Boot系列:七、 实现Mybatis多数据源切换
  10. MongoDB去重