ASP.NET 如何通过ETag实现缩略图缓存 避免页面加载刷新重复请求
解决方案
第一步:修正现有缓存配置冲突
你现有代码存在两处缓存规则冲突,需要先调整:
- 同时设置了
SetCacheability(HttpCacheability.Public)和Response.CacheControl = "private",二者优先级后者更高,建议删除context.Response.CacheControl = "private"这行,保留Public允许CDN/代理缓存缩略图,降低源站压力。 - 同时设置了
Expires为1年、MaxAge为1小时,HTTP规范中MaxAge优先级高于Expires,如果你希望图片长期缓存,将SetMaxAge改为context.Response.Cache.SetMaxAge(new TimeSpan(365, 0, 0, 0));即可。
第二步:添加ETag校验逻辑
校验逻辑要放在请求处理逻辑的最开头,无需读取文件即可返回304,最大化提升性能,完整实现代码如下:
// 优先校验ETag,放在所有逻辑最前面 string currentETag = ""; // 注意:你的ETag是从文件名生成,文件名不变的话可以直接根据fileUri拼接生成ETag,不需要先FetchFile // 这里演示和你现有生成逻辑保持一致的写法,建议可以优化为不读文件直接生成ETag var uriFetcher = new UriFetcher(fileUri); var tempPath = uriFetcher.FetchFile(); currentETag = "\"" + tempPath.Split('\\').Last() + "\""; // 获取请求头的If-None-Match var requestedETag = context.Request.Headers["If-None-Match"]; // 比对ETag,匹配直接返回304 if (!string.IsNullOrEmpty(requestedETag) && requestedETag.Trim() == currentETag) { context.Response.StatusCode = (int)HttpStatusCode.NotModified; context.Response.SuppressContent = true; return; } // 以下是原有逻辑,不需要修改 var mime = MimeType(tempPath); context.Response.Cache.SetCacheability(HttpCacheability.Public); context.Response.Cache.SetLastModified(DateTime.Now); context.Response.Cache.SetValidUntilExpires(true); context.Response.Cache.SetExpires(DateTime.Now.AddYears(1)); context.Response.Cache.SetMaxAge(new TimeSpan(365, 0, 0, 0)); context.Response.ContentType = mime; context.Response.AddHeader("ETag", currentETag); var disposition = new ContentDisposition { FileName = Path.GetFileName(tempPath), Inline = mime.Contains("image") }; context.Response.AddHeader("content-disposition", disposition.ToString()); try { context.Response.TransmitFile(tempPath); } catch { context.Response.TransmitFile(errorUri); }
额外说明
- 前端不需要做任何修改,浏览器请求图片时会自动携带
If-None-Match请求头,收到304状态码后会自动调用本地缓存的图片资源,不需要JS额外处理。 - 优化建议:因为你的ETag是基于不变的文件名生成,不需要调用
FetchFile读取文件后再生成ETag,可以直接根据fileUri参数拼接出对应的文件名生成ETag,进一步减少IO开销。
内容的提问来源于stack exchange,提问作者StealthRT
相关产品推荐
相关产品推荐

