1. 什么是 API 网关
API 网关是微服务架构中的唯一入口, 它提供一个单独且统一的 API 入口用于访问内部一个或多个 API. 它可以具有身份验证, 监控, 负载均衡, 缓存, 请求分片与管理, 静态响应处理等. API 网关方式的核心要点是, 所有的客户端和消费端都通过统一的网关接入微服务, 在网关层处理所有的非业务功能. 通常, 网关也是提供 REST/HTTP 的访问 API. 服务端通过 API-GW 注册和管理服务.
Ocelot 介绍
Ocelot 是用. net Core 实现的一款开源的网关, Ocelot 其实就是一组按照顺序排列的. net core 中间件. 它接受到请求之后用 request builder 构建一个 HttpRequestMessage 对象并发送到下游服务, 当下游请求返回到 Ocelot 管道时再由一个中间件将 HttpRequestMessage 映射到 HttpResponse 上返回客户端.
开源地址点击这里 hhttps://github.com/ThreeMammals/Ocelot
使用 Ocelot 傻瓜式转发
新建三个项目 webApi 项目, 分别命名为 ApiGateway,Api_A,Api_B
设置 Api_A 端口为 5001,Api_B 端口为 5002,ApiGateway 为 5000
为 ApiGateway 项目安装 Ocelot, 在 Nuget 中搜索 Ocelot 或者直接使用 Install-Package Ocelot 进行安装. 最新版本为 13.8.x 支持 core3.0.
在 ApiGateway 新建一个 configuration.JSON 配置文件.
- {
- "ReRoutes": [
- {
- // 上游 API 请求格式
- "UpstreamPathTemplate": "/Api_A/{controller}/{action}",
- // 网关转发到下游格式
- "DownstreamPathTemplate": "/api/{controller}/{action}",
- // 上下游支持请求方法
- "UpstreamHttpMethod": [ "GET", "POST", "DELETE", "PUT" ],
- "DownstreamScheme": "http",
- // 下游服务配置
- "DownstreamHostAndPorts": [
- {
- // 下游地址
- "Host": "localhost",
- // 下游端口号
- "Port": 5001
- }
- ]
- },
- {
- "UpstreamPathTemplate": "/Api_B/{controller}/{action}",
- "DownstreamPathTemplate": "/api/{controller}/{action}",
- "UpstreamHttpMethod": [ "GET", "POST", "DELETE", "PUT" ],
- "DownstreamScheme": "http",
- "DownstreamHostAndPorts": [
- {
- "Host": "localhost",
- "Port": 5002
- }
- ]
- }
- ]
- }
在 Startup.cs 的 ConfigureServices 和 Configure 中配置 Ocelot
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
- services.AddOcelot(new ConfigurationBuilder()
- .AddJsonFile("configuration.json")
- .Build());
- }
- public void Configure(IApplicationBuilder App, IHostingEnvironment env)
- {
- App.UseOcelot();
- if (env.IsDevelopment())
- {
- App.UseDeveloperExceptionPage();
- }
- App.UseMvc();
- }
分别为 Api_A, 和 Api_B 分别添加一个 print 接口.
- [HttpGet("print")]
- public string Print()
- {
- return "Api_A";
- }
- [HttpGet("print")]
- public string Print()
- {
- return "Api_B";
- }
测试网关
启动三个项目, 使用 postman 来调用网关
访问 Api_A 服务
访问 Api_B 服务
可以看到网关通过接受到的请求的 Url 后通过我们的配置自动转发到了我们想要访问的服务.
网关的负载均衡
当下游拥有多个节点的时候, 我们可以用 DownstreamHostAndPorts 来配置
- {
- "UpstreamPathTemplate": "/Api_A/{controller}/{action}",
- "DownstreamPathTemplate": "/api/{controller}/{action}",
- "DownstreamScheme": "https",
- "LoadBalancer": "LeastConnection",
- "UpstreamHttpMethod": [ "GET", "POST", "DELETE", "PUT" ],
- "DownstreamHostAndPorts": [
- {
- "Host": "127.0.0.1",
- "Port": 5001,
- },
- {
- "Host": "127.00.1",
- "Port": 5002,
- }
- ],
- }
LoadBalancer 是来决定负载的算法
LeastConnection: 将请求发往最空闲的那个服务器
RoundRobin: 轮流转发
NoLoadBalance: 总是发往第一个请求或者是服务发现
限流
限流可以防止上下游服务器因为过载而崩溃, 可以使用 RateLimitOptions 来配置限流
- {
- "RateLimitOptions": {
- "ClientWhitelist": ["127.0.0.1"],
- "EnableRateLimiting": true,
- "Period": "5s",
- "PeriodTimespan": 1,
- "Limit": 10
- }
- }
ClientWihteList: 白名单, 不受限流控制.
EnableRateLimiting: 使用启用限流.
Period: 限流控制的时间段 1s, 5m, 1h, 1d.
PeroidTimeSpan: 超过限流限制的次数后, 需要等待重置的时间(单位是秒).
Limit: 在限流控制时间段内最大访问数.
对于除了请求头中 ClientId=127.0.0.1 的意外所有求情启用限流, 5 秒该 API 最多10 次, 如果达到 10 次需要从第 10 次请求闭合后等待一秒进行下一次访问.
超过限流后会返回 429 状态码, 并在在返回头 (Response Header) 的 Retry-After 属性中返回等待重置时间.
限流的默认提示, code 码, 和限制标志都是可以自己配置的
- {
- "GlobalConfiguration": {
- "BaseUrl":"www.baidu.com",
- "RateLimitOptions": {
- "DisableRateLimitHeaders": false,
- "QuotaExceededMessage": "接口限流!",
- "HttpStatusCode": 200,
- "ClientIdHeader": "ClientId"
- }
- }
DisableRateLimitHeaders: 是否显示 X-Rate-Limit 和 Retry-After 头
QuotaExceededMessage: 提示信息
HttpStatusCode: 状态码
ClientIdHeader: 用来设别客户请求头, 默认为 ClientId.
BaseUrl 网关暴露的的地址.
熔断
熔断是在下游服务故障或者请求无响应的时候停止将请求转发到下游服务.
- {
- "QoSOptions": {
- "ExceptionsAllowedBeforeBreaking": 3,
- "DurationOfBreak": 20,
- "TimeoutValue": 5000
- }
- }
ExceptionsAllowedBeforeBreaking: 允许多少个异常请求.
DurationOfBreak: 熔断的时间(秒).
TimeoutValue: 下游请求的处理时间超过多少则将请求设置为超时.
缓存
Ocelot 可以对下游请求结果进行缓存, 主要是依赖于 CacheManager 来实现的.
- {
- "FileCacheOptions": {
- "TtlSeconds": 60,
- "Region": "key"
- }
- }
TtlSeconds: 缓存时间(秒).
Region: 缓存分区名
我们可以调用 Ocelot 的 API 来移除某个区下面的缓存 .
请求头的转化
Ocelot 允许在请求下游服务之前和之后转换 Header. 目前 Ocelot 只支持查找和替换.
如果们需要转发给下游的 Header 重添加一个 key/value
- {
- "UpstreamHeaderTransform": {
- "demo": "xxxxxxx"
- }
- }
如果们需要在返回给客户端的的 Header 中添加一个 key/value
- {
- "DownstreamHeaderTransform": {
- "demo": "xxxxxxx"
- }
- }
如果我们需要替换 Heaher 中某些值
- {
- // 请求
- "UpstreamHeaderTransform": {
- "demo": "a,b"
- },
- // 响应
- "DownstreamHeaderTransform":
- {
- "demo": "a,b"
- }
- }
语法是{find},{replace}, 利用 b 取代 a
在 Header 转换中可以使用占位符
{BaseUrl} - 这个是 Ocelot 暴露在外的 url. 例如 http://localhost:5000/.
{DownstreamBaseUrl} - 这个是下游服务的基本 url 例如 http://localhost:5001/. 目前这个只在 DownstreamHeaderTransform 中起作用.
{TraceId} - 这个是 Butterfly 的跟踪 id. 目前这个也只在 DownstreamHeaderTransform 中起作用
如果您想将 location 头返回给客户端, 可能需要将 location 更改为 Ocelot 的地址而不是下游服务地址. Ocelot 可以使用以下配置实现.
- {
- "DownstreamHeaderTransform": {
- "Location": "{DownstreamBaseUrl},{BaseUrl}"
- },
- }
给 Header 中添加下游地址
响应的 Header 中已经替换成 BaseUrl 了
总结
简单的实现了通过网关来访问 API 接口. ocelot 功能远不止这些, 之后会实现与 IdentityServer 的认证鉴权. 服务发现.
来源: https://www.cnblogs.com/linhuiy/p/12029652.html