ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

D_05 API缓存过滤器(aop方式实现缓存)

2022-07-24 10:06:43  阅读:129  来源: 互联网

标签:缓存 return 05 API context 过滤器 HttpContext public


功能描述

为了提升服务接口的性能,所以需要添加缓存。为了尽量避免添加缓存对业务代码的侵入性,所以采用aop模式(过滤器)来实现缓存功能。api缓存过滤器具备一下的能力。

(1)在过滤器中实现缓存功能,如果key存在则直接返回结果,如果不存在则进入业务层,在业务层处理完成后回到过滤器完成对缓存的更新插入;

(2)能够灵活的生成缓存key,进而实现缓存的不同场景,如可以根据路由-接口方法-参数,能动态识别get、post、put、delete方式性能,进而生成灵活的key值;

(3)api缓存过滤器是非全局的,根据自己业务按需通过特性的方式加载方法上;

(4)特性支持设置key(支持通配符)、缓存时间、是否启用缓存波动时间(可解决缓存雪崩)

(5)提供缓存过滤器ApiCache:,示例: [ApiCache("UserRoles:{id}", ApplicationConst.Cache.ApiCacheTime,true)],同时提供移除缓存过滤器,示例: [ApiCacheRemove("UserRoles:{id}")],在更新的接口中可以通过该特性动态的删除缓存,保证数据一直性。

(6)api缓存过滤器基本可以上可以覆盖常规业务上的缓存用法,但实现缓存时该方式并不是强制性的,可以根据具体情况进行选择。优先选用缓存过滤器、如果针对默写复杂的业务场景,可以降级混用,甚至再降级采用在业务代码层实现缓存。

示例截图:

 

 

设计

 缓存的流程图

 

 

代码实现

api缓存过滤器实现代码

/// <summary>
    /// 接口缓存过滤器,备注:
    /// 1.适用于输入参数简单的接口缓存,例如根据Id获取实体,不适用于分页查询接口缓存;
    /// 2.禁用并更新缓存:Http请求头或者Url参数增加'DisableCache';
    /// 3.注意缓存键模式参数'KeyPattern'要唯一,不要与其他缓存冲突;
    /// 4.只对返回值类型为通用接口类型'ApiResult'的接口进行缓存;
    /// 5.在更新和删除接口方法上使用'ApiCacheRemove'特性进行缓存的删除;
    /// 6.模板类型参数名称注意大小写,Json对大小写敏感,Http首部Hearder,路由参数及Url参数对大小写不敏感,所以从Json中解析参数值时需保证参数名与模板参数名称大小写一致;
    /// </summary>
    public class ApiCacheAttribute : ActionFilterAttribute
    {
        /// <summary>
        /// 缓存键模式
        /// </summary>
        public string KeyPattern { get; set; }

        /// <summary>
        /// 缓存分钟
        /// </summary>
        public int CacheMinutes { get; set; }

        /// <summary>
        /// 是否添加随机值(预防缓存雪崩),默认:true
        /// </summary>
        public bool EnableRandomTime { get; set; }

        private RedisClient _redisClient;
        private ICurrentTenant _currentTenant;
        private string _cacheKey;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="keyPattern">缓存键模式</param>
        /// <param name="cacheMinutes">缓存分钟</param>
        /// <param name="enableRandomTime">是否添加随机值(预防缓存雪崩)</param>
        public ApiCacheAttribute(string keyPattern, int cacheMinutes = 5, bool enableRandomTime = true)
        {
            KeyPattern = keyPattern;
            CacheMinutes = cacheMinutes;
            EnableRandomTime = enableRandomTime;
        }

        public override void OnActionExecuting(ActionExecutingContext context)
        {
            _redisClient = context.HttpContext.RequestServices.GetRequiredService<RedisClient>();
            _currentTenant = context.HttpContext.RequestServices.GetRequiredService<ICurrentTenant>();
            _cacheKey = KeyPattern.ToApiCacheKey(context.HttpContext.Request, _currentTenant.Id);

            if (context.HttpContext.Request.Query != null && context.HttpContext.Request.Query.ContainsKey("DisableCache")
                || context.HttpContext.Request.Headers.ContainsKey("DisableCache"))
            {
                return;
            }

            string apiResultStr = _redisClient.StringGet(_cacheKey);
            if (!string.IsNullOrWhiteSpace(apiResultStr))
            {
                var content = new ContentResult();
                content.Content = apiResultStr;
                content.ContentType = "application/json; charset=utf-8";
                content.StatusCode = 200;
                context.HttpContext.Response.Headers.Add("CacheData", _cacheKey);
                context.Result = content;
            }
        }

        public override void OnActionExecuted(ActionExecutedContext context)
        {
            if (context.Exception != null) return;
            if (context.Result == null) return;
            var objResult = context.Result as ObjectResult;
            if (objResult.DeclaredType != typeof(ApiResult)) return;
            var apiResult = objResult.Value as ApiResult;
            if (apiResult.Code != (int)ApiEnum.Success) return;

            var expireTime = TimeSpan.FromMinutes(CacheMinutes);
            if (apiResult.Data == null)
            {
                //如果数据不存在,则把空值缓存起来并把过期时间设置为一个比较短的时间,目的是对缓存击穿进行一定控制
                expireTime = TimeSpan.FromMinutes(1);
            }
            if (EnableRandomTime)
            {
                expireTime += TimeSpan.FromSeconds(new Random().Next(300));
            }

            var jsonSettings = JsonSerializerSettingsProvider.CreateSerializerSettings();
            jsonSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
            jsonSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;

            var apiResultStr = JsonConvert.SerializeObject(apiResult, jsonSettings);

            _redisClient.StringSet(_cacheKey, apiResultStr, expireTime);
        }
    }

 

api缓存移除过滤器实现代码

/// <summary>
    /// 接口缓存删除过滤器
    /// </summary>
    public class ApiCacheRemoveAttribute : ActionFilterAttribute
    {
        /// <summary>
        /// 缓存键模式,备注:
        /// 1.模板类型参数名称注意大小写,Json对大小写敏感,Http首部Hearder,路由参数及Url参数对大小写不敏感,所以从Json中解析参数值时需保证参数名与模板参数名称大小写一致;
        /// </summary>
        public string KeyPattern { get; set; }

        private RedisClient _redisClient;
        private ICurrentTenant _currentTenant;
        private string _cacheKey;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="keyPattern">缓存键模式</param>
        public ApiCacheRemoveAttribute(string keyPattern)
        {
            KeyPattern = keyPattern;
        }

        public override void OnActionExecuted(ActionExecutedContext context)
        {
            if (context.Exception != null) return;
            if (context.Result == null) return;
            var objResult = context.Result as ObjectResult;
            if (objResult.DeclaredType != typeof(ApiResult)) return;
            var apiResult = objResult.Value as ApiResult;
            if (apiResult.Code != (int)ApiEnum.Success) return;

            _redisClient = context.HttpContext.RequestServices.GetRequiredService<RedisClient>();
            _currentTenant = context.HttpContext.RequestServices.GetRequiredService<ICurrentTenant>();

            _cacheKey = KeyPattern.ToApiCacheKey(context.HttpContext.Request, _currentTenant.Id);

            _redisClient.KeyDelete(_cacheKey);



            
        }
    }

 

标签:缓存,return,05,API,context,过滤器,HttpContext,public
来源: https://www.cnblogs.com/hjwcore/p/16513873.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有