C# 来自HttpHandler的图像赢得';浏览器中的t缓存
我正在使用IHttpHandler从数据库中提供一个图像。相关代码如下:C# 来自HttpHandler的图像赢得';浏览器中的t缓存,c#,.net,asp.net,ihttphandler,C#,.net,Asp.net,Ihttphandler,我正在使用IHttpHandler从数据库中提供一个图像。相关代码如下: public void ProcessRequest(HttpContext context) { context.Response.ContentType = "image/jpeg"; int imageID; if (int.TryParse(context.Request.QueryString["id"], out imageID)) { var photo = n
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "image/jpeg";
int imageID;
if (int.TryParse(context.Request.QueryString["id"], out imageID))
{
var photo = new CoasterPhoto(imageID);
if (photo.CoasterPhotoID == 0)
context.Response.StatusCode = 404;
else
{
byte[] imageData = GetImageData(photo);
context.Response.OutputStream.Write(imageData, 0, imageData.Length);
context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.Cache.SetExpires(DateTime.Now.AddMinutes(5));
context.Response.Cache.SetLastModified(photo.SubmitDate);
}
}
else
context.Response.StatusCode = 404;
}
问题是浏览器不会缓存图像,可能是因为我没有在响应头中指明正确的内容。HttpCachePolicy属性上调用方法的部分是我认为会迫使浏览器保留图像的部分,但事实并非如此。我认为“正确”的做法是处理程序返回一个304状态代码而不带图像,对吗?如何使用IHttpHandler实现这一点
编辑:
根据最佳答案,我运行了这段代码,它完全解决了问题。是的,它需要一些重构,但它通常展示了我所追求的。有关部分:
if (!String.IsNullOrEmpty(context.Request.Headers["If-Modified-Since"]))
{
CultureInfo provider = CultureInfo.InvariantCulture;
var lastMod = DateTime.ParseExact(context.Request.Headers["If-Modified-Since"], "r", provider).ToLocalTime();
if (lastMod == photo.SubmitDate)
{
context.Response.StatusCode = 304;
context.Response.StatusDescription = "Not Modified";
return;
}
}
byte[] imageData = GetImageData(photo);
context.Response.OutputStream.Write(imageData, 0, imageData.Length);
context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.Cache.SetLastModified(photo.SubmitDate);
您是否有任何响应缓冲发生?如果是这样,您可能希望在写入输出流之前设置头。i、 e.尝试将
Response.OutputStream.Write()
行向下移动到缓存设置行下方。好的,您负责发送304 Not Modified,这意味着在.Net framework中,在您发送“动态”图像数据的这个用例中,我不知道有什么东西可以帮您做到这一点。必须执行的操作(在伪代码中):
- 检查请求中的If-Modified-Since头并解析出日期(如果存在)
- 将其与原始图像(动态生成)的上次修改日期进行比较。跟踪这可能是这个问题解决方案中最复杂的部分。在您当前的情况下,您正在根据每个请求重新创建图像;除非你万不得已,否则你不会想那样做
- 如果浏览器拥有的文件日期较新或与您拥有的图像日期相同,请发送304 Not Modified
- 否则,请继续当前的实现
我知道这听起来有点复杂,但值得。我最近刚刚实现了这种方法,在处理时间和带宽使用方面的节省令人难以置信。如果磁盘上有源文件,您可以使用以下代码:
context.Response.AddFileDependency(pathImageSource);
context.Response.Cache.SetETagFromFileDependencies();
context.Response.Cache.SetLastModifiedFromFileDependencies();
context.Response.Cache.SetCacheability(HttpCacheability.Public);
另外,请确保使用IIS而不是Visual Studio进行测试。ASP.NET开发服务器(又名Cassini)始终将缓存控制设置为私有
另请参见:这是如何在(.NET wiki)文件处理程序中完成的:
FileInfo info = new FileInfo(fullPath);
TimeSpan expires = TimeSpan.FromDays(28);
context.Response.Cache.SetLastModifiedFromFileDependencies();
context.Response.Cache.SetETagFromFileDependencies();
context.Response.Cache.SetCacheability(HttpCacheability.Public);
int status = 200;
if (context.Request.Headers["If-Modified-Since"] != null)
{
status = 304;
DateTime modifiedSinceDate = DateTime.UtcNow;
if (DateTime.TryParse(context.Request.Headers["If-Modified-Since"], out modifiedSinceDate))
{
modifiedSinceDate = modifiedSinceDate.ToUniversalTime();
DateTime fileDate = info.LastWriteTimeUtc;
DateTime lastWriteTime = new DateTime(fileDate.Year, fileDate.Month, fileDate.Day, fileDate.Hour, fileDate.Minute, fileDate.Second, 0, DateTimeKind.Utc);
if (lastWriteTime != modifiedSinceDate)
status = 200;
}
}
context.Response.StatusCode = status;
Thomas关于IIS不提供状态码的回答是关键,没有状态码,每次只能返回200秒
浏览器只需向您发送它认为文件上次被修改的日期和时间(完全没有标题),因此如果它不同,您只需返回200。您确实需要规范化文件的日期,以删除毫秒并确保它是UTC日期
如果有一个有效的修改,我将默认设置为304s,但如果需要,可以进行调整。看起来浏览器应该将其缓存5分钟。它会缓存那么长时间吗?这就是你想要的吗?浏览器根本不缓存。此代码在每次发出请求时都会执行。完全不相关,但在使用此方法提供图像时,您是否有任何性能影响?特别是当您使用IHttpHandler在一个网页中提供多个图像时?因为我正在写入流而不是文件?请小心(lastMod==photo.SubmitDate)行,正如我所看到的,lastMod参数只能解析为秒,而不是毫秒-在我的例子中,它无法与file.creatorDateTime()进行比较,因为:)