.NET Web API自定义CacheFilter缓存不生效问题排查
问题原因及解决方案
你当前实现的CacheFilter仅完成了客户端缓存响应头配置,没有实现服务端侧的响应缓存逻辑,这是预期不生效的核心原因,具体存在两点问题:
- 你设置的
CacheControl响应头仅用于告知客户端/代理节点如何缓存当前响应,不会阻止请求打到服务端:只要请求到达服务端,GetGuid方法都会执行生成新的Guid,你配置的100秒缓存只是客户端本地的缓存规则,如果你是强制刷新页面、或者客户端配置了忽略缓存,请求仍会触发服务端逻辑。 - 你没有实现缓存命中的拦截逻辑:即使客户端携带缓存验证头发起请求,你的过滤器也没有做有效性校验,仍会完整执行Action逻辑返回新结果。
方案1:使用官方成熟的响应缓存组件(推荐)
ASP.NET Web API 2 可直接安装Microsoft.AspNet.WebApi.OutputCache NuGet包,直接使用特性标记即可,无需自己实现过滤逻辑:
// 安装包后直接标记方法即可 [CacheOutput(ClientTimeSpan = 100, ServerTimeSpan = 100)] public Guid GetGuid() { return Guid.NewGuid(); }
如果是ASP.NET Core Web API,直接使用原生的[ResponseCache]特性,同时在Program.cs中开启响应缓存中间件即可。
方案2:完善自定义CacheFilter逻辑
如果需要自己实现缓存逻辑,需要同时实现请求前缓存校验和请求后缓存存储两个逻辑,参考代码如下:
public class CacheFilter : ActionFilterAttribute { public int TimeDurationInSecs { get; set; } // 用MemoryCache做服务端缓存存储,多实例部署可替换为分布式缓存 private static readonly MemoryCache _cache = MemoryCache.Default; public override void OnActionExecuting(HttpActionContext actionContext) { // 生成唯一缓存key:包含控制器名、Action名、请求参数 var key = $"{actionContext.ControllerContext.ControllerDescriptor.ControllerName}_{actionContext.ActionDescriptor.ActionName}_{string.Join("_", actionContext.ActionArguments.Select(kv => kv.Value))}"; var cachedResponse = _cache.Get(key) as HttpResponseMessage; if (cachedResponse != null) { // 缓存命中直接返回缓存结果,不执行Action actionContext.Response = cachedResponse; return; } base.OnActionExecuting(actionContext); } public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { if (actionExecutedContext.Response != null && actionExecutedContext.Response.IsSuccessStatusCode) { // 生成和OnActionExecuting一致的缓存key var key = $"{actionExecutedContext.ActionContext.ControllerContext.ControllerDescriptor.ControllerName}_{actionExecutedContext.ActionContext.ActionDescriptor.ActionName}_{string.Join("_", actionExecutedContext.ActionContext.ActionArguments.Select(kv => kv.Value))}"; // 把响应存入缓存 _cache.Add(key, actionExecutedContext.Response, DateTimeOffset.Now.AddSeconds(TimeDurationInSecs)); // 配置客户端缓存头 actionExecutedContext.Response.Headers.CacheControl = new CacheControlHeaderValue { MaxAge = TimeSpan.FromSeconds(TimeDurationInSecs), MustRevalidate = true, Public = true }; } base.OnActionExecuted(actionExecutedContext); } }
内容的提问来源于stack exchange,提问作者JS.
相关产品推荐
相关产品推荐

