ASP.NET Core 7中Cache-Control引发的浏览器异常行为问题
我们采用**Flutter -> ASP.NET Core 7(仅API+托管Flutter构建资源)**技术栈开发安卓和Web应用:
- 初始问题:Web端浏览器未下载Flutter最新构建包,即使修改了HTML链接的查询字符串,最终通过给
index.html添加强制不缓存头解决:app.UseStaticFiles(new StaticFileOptions { // disabled cache for index.html OnPrepareResponse = ctx => { if (ctx.File.Name == "index.html") { ctx.Context.Response.Headers.Append("Cache-Control", "no-cache, no-store, must-revalidate"); ctx.Context.Response.Headers.Append("Pragma", "no-cache"); ctx.Context.Response.Headers.Append("Expires", "0"); } } }); - 新问题:上述配置生效后,Chrome/Edge浏览器(或Flutter Web)开始缓存所有API响应,尽管API的响应头在修改前后无变化。后续通过添加针对
/api路由的NoCache中间件解决:using Microsoft.AspNetCore.Http; using System.Threading.Tasks; namespace GlobalAttributes.WebServices.Middleware; public class NoCacheMiddleware { private readonly RequestDelegate _next; public NoCacheMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { if (context.Request.Path.StartsWithSegments("/api")) { context.Response.Headers["Cache-Control"] = "no-cache, no-store, must-revalidate"; context.Response.Headers["Pragma"] = "no-cache"; context.Response.Headers["Expires"] = "0"; } await _next(context); } } - 特殊情况:该API缓存问题无法在任何测试环境(包括本地独立IIS实例)复现,仅生产环境出现。
1. 生产环境IIS的隐性缓存规则触发
测试环境通常是开发服务器(Kestrel)或无额外配置的IIS,而生产环境的IIS可能启用了输出缓存模块(Output Cache)或ARR(应用请求路由)缓存。当index.html设置了明确的no-cache头后,IIS的缓存策略可能发生连锁调整:原本对无缓存头的API请求,IIS可能默认不缓存,但当检测到同站点有资源强制不缓存时,可能触发反向的缓存逻辑(比如为平衡性能,对无明确缓存指令的API启用缓存)。
2. 浏览器缓存启发式策略的变化
浏览器对无明确缓存头的响应,会使用启发式缓存规则(比如基于响应的Last-Modified头计算缓存时长)。当页面核心资源index.html被强制设置为no-cache后,浏览器可能调整了同源请求的缓存优先级:原本对API这类动态请求,浏览器可能倾向于不缓存,但当核心页面强制刷新后,浏览器可能误将无缓存头的API响应判定为可缓存静态资源,或启用了更激进的启发式缓存时长。
3. ASP.NET Core中间件管道的隐性影响
UseStaticFiles中间件的配置可能改变了响应头管道的处理逻辑。如果UseStaticFiles在UseRouting或UseEndpoints之前注册,当它为index.html添加缓存头后,可能干扰后续API请求的响应头处理——比如ASP.NET Core的默认响应头生成逻辑被覆盖,原本应为API添加的隐性Cache-Control头(比如private)未被正确设置,导致浏览器启用默认缓存。
4. Flutter Web的网络层缓存行为调整
Flutter Web的HttpClient或底层浏览器Fetch API,可能对同源页面的缓存状态存在关联逻辑:当index.html被标记为no-cache后,Flutter Web的网络请求层可能切换了缓存模式,不再默认跳过对无缓存头API的缓存,而是遵循浏览器的启发式规则,导致API响应被缓存。
内容的提问来源于stack exchange,提问作者user1827389

