ASP.NET Core 中的响应缓存中间件

客户端(浏览器)缓存

通过设置HTTP的响应头来完成

1、直接用Response对象去设置

[HttpGet]
        public IEnumerable<WeatherForecast> Get()
        {
            Console.WriteLine("服务响应");
            //直接一,简单粗暴,不要拼写错了就好~~
            Response.Headers[Microsoft.Net.Http.Headers.HeaderNames.CacheControl] = "public, max-age=600";

            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();
        }
View Code

查看http响应头

 

上面的示例设置客户端缓存600秒,如果直接刷新浏览器或者按F5进行刷新,缓存会失效(cache-control对刷新无效)

 

2、用responsecacheAttribute类设置缓存

  [HttpGet]
        [responsecache(Duration = 100)]
        public IEnumerable<WeatherForecast> Get()
        {
            Console.WriteLine("服务响应");
            ////直接一,简单粗暴,不要拼写错了就好~~
            //Response.Headers[Microsoft.Net.Http.Headers.HeaderNames.CacheControl] = "public, max-age=600";

            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();
        }
View Code

 

 

 

 效果和上面是一致的,通过源码分析发现responsecacheAttribute也是通过设置http头来实现的。

 /// <summary>
    /// Specifies the parameters necessary for setting appropriate headers in response caching.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public class responsecacheAttribute : Attribute, IFilterFactory, IOrderedFilter
    {
        
        /// <inheritdoc />
        public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
        {
            if (serviceProvider == null)
            {
                throw new ArgumentNullException(nameof(serviceProvider));
            }

            var loggerFactory = serviceProvider.GetrequiredService<ILoggerFactory>();
            var optionsAccessor = serviceProvider.GetrequiredService<IOptions<Mvcoptions>>();
            var cacheProfile = GetCacheProfile(optionsAccessor.Value);

            // responsecacheFilter cannot take any null values. Hence, if there are any null values,
            // the properties convert them to their defaults and are passed on.
            return new responsecacheFilter(cacheProfile, loggerFactory);
        }
    }
View Code

responsecacheFilter部分代码如下

/// <summary>
    /// An <see cref="IActionFilter"/> which sets the appropriate headers related to response caching.
    /// </summary>
    internal class responsecacheFilter : IActionFilter, IresponsecacheFilter
    {
         
        /// <inheritdoc />
        public void OnActionExecuting(ActionExecutingContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            // If there are more filters which can override the values written by this filter,
            // then skip execution of this filter.
            var effectivePolicy = context.FindEffectivePolicy<IresponsecacheFilter>();
            if (effectivePolicy != null && effectivePolicy != this)
            {
                _logger.NotMostEffectiveFilter(GetType(), effectivePolicy.GetType(), typeof(IresponsecacheFilter));
                return;
            }

            _executor.Execute(context);
        }

         
    }
View Code

具体的实现是在responsecacheFilterExecutor类中,代码如下

internal class responsecacheFilterExecutor
    {
       
        public void Execute(FilterContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (!NoStore)
            {
                // Duration MUST be set (either in the cache profile or in this filter) unless NoStore is true.
                if (_cacheProfile.Duration == null && _cacheDuration == null)
                {
                    throw new InvalidOperationException(
                        Resources.Formatresponsecache_SpecifyDuration(nameof(NoStore), nameof(Duration)));
                }
            }

            var headers = context.HttpContext.Response.Headers;

            // Clear all headers
            headers.Remove(HeaderNames.vary);
            headers.Remove(HeaderNames.CacheControl);
            headers.Remove(HeaderNames.Pragma);

            if (!string.IsNullOrEmpty(varyByHeader))
            {
                headers[HeaderNames.vary] = varyByHeader;
            }

            if (varyByQueryKeys != null)
            {
                var responseCachingFeature = context.HttpContext.Features.Get<IResponseCachingFeature>();
                if (responseCachingFeature == null)
                {
                    throw new InvalidOperationException(
                        Resources.FormatvaryByQueryKeys_Requires_ResponseCachingMiddleware(nameof(varyByQueryKeys)));
                }
                responseCachingFeature.varyByQueryKeys = varyByQueryKeys;
            }

            if (NoStore)
            {
                headers[HeaderNames.CacheControl] = "no-store";

                // Cache-control: no-store, no-cache is valid.
                if (Location == responsecacheLocation.None)
                {
                    headers.AppendCommaSeparatedValues(HeaderNames.CacheControl, "no-cache");
                    headers[HeaderNames.Pragma] = "no-cache";
                }
            }
            else
            {
                string cacheControlValue;
                switch (Location)
                {
                    case responsecacheLocation.Any:
                        cacheControlValue = "public,";
                        break;
                    case responsecacheLocation.Client:
                        cacheControlValue = "private,";
                        break;
                    case responsecacheLocation.None:
                        cacheControlValue = "no-cache,";
                        headers[HeaderNames.Pragma] = "no-cache";
                        break;
                    default:
                        cacheControlValue = null;
                        break;
                }

                cacheControlValue = $"{cacheControlValue}max-age={Duration}";
                headers[HeaderNames.CacheControl] = cacheControlValue;
            }
        }
    }
View Code

通过源码分析已经知道了responsecacheAttribute运作的基本原理,下面再来看看如何配置出其他不同的效果

   
   
   
   

相关文章

数组的定义 Dim MyArray MyArray = Array(1‚5‚123‚12‚98...
\'参数: \'code:要检测的代码 \'leixing:html或者ubb \'n...
演示效果: 代码下载: 点击下载
环境:winxp sp2 ,mysql5.0.18,mysql odbc 3.51 driver 表采...
其实说起AJAX的初级应用是非常简单的,通俗的说就是客户端(j...
<% ’判断文件名是否合法 Function isFilename(aFilename...