ASP.NET Core 10.0.9 后自定义输出缓存不再命中,检查响应阶段的认证判断
认证请求的自定义输出缓存突然失效,检查响应阶段 DefaultPolicy 是否再次清除 AllowCacheStorage。区分回移合入与正式运行时,保留 Cookie、身份和个性化数据的缓存限制。
升级到 ASP.NET Core 10.0.9 后,同一个 GET 接口每次都重新生成内容,没有异常,响应本身也正确;自定义 IOutputCachePolicy 明明已把 AllowCacheStorage 设为 true。如果这个策略原本允许已认证用户访问一份与身份无关的公共响应,要检查默认策略在响应阶段是否又关闭了存储。
这条回归在 10.0.9 到已核对的 10.0.12 中存在。普通匿名接口不一定受影响;默认就不允许认证响应缓存的应用,也不能把低命中率归到这里。
请求阶段允许,不代表最终会写入缓存
默认输出缓存只缓存符合条件的 GET/HEAD、200 响应,并排除认证请求与设置 Cookie 的响应。自定义策略在请求阶段覆盖默认决定,是扩展缓存规则的一种方式。
10.0.9 增加了响应阶段的认证检查:DefaultPolicy.ServeResponseAsync 发现用户已认证后,会再次把 AllowCacheStorage 清为 false。自定义策略若只在 CacheRequestAsync 中打开存储,在 ServeResponseAsync 中什么也不做,最后仍不会写入缓存。
因此,单独构造一个 AllowCacheStorage = true 的上下文测试自定义策略,可能完全通过,却覆盖不到实际中间件先调用默认策略的顺序。查看完整管线中的状态变化,尤其是默认策略执行后的值。
可以先记录实际服务的框架版本,而不是只看项目的目标框架:
dotnet --list-runtimes
这条命令查看当前环境安装的运行时。框架依赖部署还需核对应用实际选择的版本;自包含部署要查发布产物自身,服务器上另一份运行时不决定它的行为。
用不涉及用户数据的端点确认
在隔离环境选择一个明确与用户、租户和授权范围无关的测试响应,例如当前生成时间。保留与故障一致的认证、中间件顺序和命名缓存策略,连续请求同一个地址,检查返回体是否复用、服务端是否重复执行生成代码。Age 头可以作为辅助观察,不能单靠缺少这个头就断言无缓存。
对照时记录三个位置:请求阶段自定义策略结束、响应阶段默认策略结束、响应阶段自定义策略结束。若存储许可由 true 变成 false,且恰好发生在默认策略的已认证分支,才与这条回归吻合。
如果请求根本没进入指定策略、响应设置了 Cookie、状态码不是 200,或缓存键因查询字符串不断变化,应先处理这些实际差异。把 Cache-Control 响应头改成 public,也不会自动改掉输出缓存的策略状态。
不要只在响应阶段无条件设回 true
这样做能使某些样例恢复命中,却可能覆盖 Cookie、状态码、认证时机等其他禁止存储的决定。尤其是中间件之后才完成认证的请求,不能因为这个补丁被放进共享缓存。用户资料、租户数据和按权限裁剪的响应也不能套用公共缓存策略。
在无法安全证明响应与身份无关时,临时保持这条路径不缓存,并评估生成开销,是更可控的处理。不要为恢复命中率把默认安全条件全部移除,或退回缺少其他修正的旧运行时。
针对该问题的源码修正已经合入 release/10.0:请求阶段记录用户是否已经认证,响应阶段只额外拦住后来才变成已认证的请求,保留此前自定义策略的选择。分支合入不能当作正式运行时已经包含修复;采用维护版本前,需要核对该版本的发布内容和实际产物。
如果应用已有完整的自定义响应策略,确需临时调整,应重新计算自己的全部允许条件,保留状态码、Cookie、方法、身份与缓存键规则,并覆盖真实中间件顺序的集成检查。不要从一行 AllowCacheStorage = true 推导出一份完整策略。
完成更新后,同时验证符合条件的公共响应能够复用,个性化响应、设置 Cookie 的响应及晚于输出缓存完成认证的请求仍不被共享。恢复命中只能说明缓存路径工作,不能替代权限与隔离检查。


