Ocelot中使用 CacheManager 来支持缓存,官方文档中强烈建议使用该包作为缓存工具。
以下介绍通过使用CacheManager来实现Ocelot缓存。

1、通过Nuget添加 Ocelot.Cache.CacheManager 包

在OcelotGetway项目中添加引用

.Netcore 2.0 Ocelot Api网关教程(8)- 缓存_分享
Add cache package.png

2、修改 Startup 中的 ConfigureServices 方法

修改如下:

services
    .AddOcelot(new ConfigurationBuilder()
    .AddJsonFile("configuration.json")
          .Build())
    .AddConsul()
    .AddCacheManager(x => x.WithDictionaryHandle())
    .AddAdministration("/administration", "secret");

3、修改 WebApiA 添加一个 TimeController 并添加如下代码:

using System;
using Microsoft.AspNetCore.Mvc;

namespace WebApiA.Controllers
{
    [Produces("application/json")]
    [Route("api/[controller]/[action]")]
    public class TimeController : Controller
    {
        [HttpGet]
        public string GetNow()
        {
            return DateTime.Now.ToString("hh:mm:ss");
        }
    }
}

启动WebApiA项目并使用Postman多次请求 http://localhost:5000/api/Time/GetNow

 
.Netcore 2.0 Ocelot Api网关教程(8)- 缓存_分享_02
 
.Netcore 2.0 Ocelot Api网关教程(8)- 缓存_分享_03

可以看到每次返回的时间不同。

4、修改OcelotGetway项目中的 configuration.json,在 ReRoutes 中添加如下配置:

{
    "DownstreamPathTemplate": "/api/Time/GetNow",
    "DownstreamScheme": "http",
    "DownstreamHostAndPorts": [
      {
        "Host": "localhost",
        "Port": 5001
      }
    ],
    "UpstreamPathTemplate": "/Now",
    "UpstreamHttpMethod": [ "Get" ],
    "FileCacheOptions": {
      "TtlSeconds": 60,
      "Region": "somename"
    }
}

对 FileCacheOptions 配置做下解释:

  • TtlSeconds: 缓存时间(秒)
  • Region: 缓存区,表示改配置缓存放到哪个区域,可以在配置管理中进行维护,后边将做详细介绍
    用一句话解释改配置:对链接http://localhost:5000/Now使用somename缓存区进行60秒缓存。
    然后启动OcelotGetway项目,使用Postman请求如下:

    多次请求在一分钟之内得到的返回数据并未发生变化。
    至此,缓存配置完成。

5、使用配置管理清除缓存

在配置管理篇中并没有介绍清除缓存api的使用,而是留到了本片来进行介绍。要使用配置管理需要先按照之前的文章进行配置。
以下介绍清除缓存的方法。
使用Postman post请求http://localhost:5000/administration/connect/token如下:

 
.Netcore 2.0 Ocelot Api网关教程(8)- 缓存_分享_04
 

得到token。
使用Postman delete请求http://localhost:5000/administration/outputcache/somename并bearer上述得到的token如下:

 
.Netcore 2.0 Ocelot Api网关教程(8)- 缓存_分享_05

再次请求http://localhost:5000/Now,可以发现与上次请求的返回时间不同。

注意:两次请求http://localhost:5000/Now的时间间隔要控制在60s之内才能看出效果。

6、实现自己的缓存

Ocelot提供了接口可以让我们自己实现缓存处理类,该类要实现 IOcelotCache<CachedResponse>,并且要在 Startup中的 ConfigureServices 方法中的 AddOcelot 之后添加 services.AddSingleton<IOcelotCache<CachedResponse>, MyCache>(); 来注入自己的缓存处理类覆盖Ocelot中默认的缓存处理。
如果需要实现文件缓存需要实现 IOcelotCache<FileConfiguration> 接口并添加相应注入。
提供一个简单版本的缓存处理类(非常不建议生产环境使用):

using System;
using System.Collections.Generic;
using System.Linq;
using Ocelot.Cache;

namespace OcelotGetway
{
    public class MyCache : IOcelotCache<CachedResponse>
    {
        private static Dictionary<string, CacheObj> _cacheObjs = new Dictionary<string, CacheObj>();
        
        public void Add(string key, CachedResponse value, TimeSpan ttl, string region)
        {
            if (!_cacheObjs.ContainsKey($"{region}_{key}"))
            {
                _cacheObjs.Add($"{region}_{key}", new CacheObj()
                {
                    ExpireTime = DateTime.Now.Add(ttl),
                    Response = value
                });
            }
        }

        public CachedResponse Get(string key, string region)
        {
            if (!_cacheObjs.ContainsKey($"{region}_{key}")) return null;
            
            var cacheObj = _cacheObjs[$"{region}_{key}"];
            if (cacheObj != null && cacheObj.ExpireTime >= DateTime.Now)
            {
                return cacheObj.Response;
            }

            _cacheObjs.Remove($"{region}_{key}");
            return null;

        }

        public void ClearRegion(string region)
        {
            var keysToRemove = _cacheObjs.Where(c => c.Key.StartsWith($"{region}_"))
                .Select(c => c.Key)
                .ToList();
            foreach (var key in keysToRemove)
            {
                _cacheObjs.Remove(key);
            }

        }

        public void AddAndDelete(string key, CachedResponse value, TimeSpan ttl, string region)
        {
            if (_cacheObjs.ContainsKey($"{region}_{key}"))
            {
                _cacheObjs.Remove($"{region}_{key}");
            }
            
            _cacheObjs.Add($"{region}_{key}", new CacheObj()
            {
                ExpireTime = DateTime.Now.Add(ttl),
                Response = value
            });
        }
    }

    public class CacheObj
    {
        public DateTime ExpireTime { get; set; }

        public CachedResponse Response { get