una navegadores navegador mac los evitar eliminar con como chrome caché cache borrar aplicación actualizar c# .net asp.net ihttphandler

c# - navegadores - La imagen de HttpHandler no se almacenará en caché en el navegador



evitar cache html (4)

Estoy sirviendo una imagen de una base de datos utilizando un IHttpHandler. El código relevante está aquí:

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; }

El problema es que el navegador no almacena en caché la imagen, presumiblemente porque no estoy indicando lo correcto en los encabezados de respuesta. Los métodos de llamada de partes en la propiedad HttpCachePolicy es lo que pensé que forzaría al navegador a mantener la imagen, pero no lo hace. Creo que lo "correcto" es que el controlador devuelva un código de estado 304 sin una imagen, ¿verdad? ¿Cómo lo logro usando IHttpHandler?

EDITAR:

Por la mejor respuesta, tengo este código en ejecución y resuelve completamente el problema. Sí, necesita algo de refactorización, pero generalmente demuestra lo que estaba buscando. Las partes relevantes:

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);


¿Tiene algún búfer de respuesta sucediendo? Si es así, es posible que desee establecer los encabezados antes de escribir en la secuencia de salida. es decir, intente mover la línea Response.OutputStream.Write() hacia abajo debajo de las líneas de configuración de la memoria caché.


AFAIK, usted es responsable de enviar 304 No modificado, lo que significa que no tengo conocimiento de nada en el marco .Net que lo haga por usted en este caso de uso de que envíe datos de imagen "dinámicos". Lo que tendrás que hacer (en pseudo código):

  • Verifique el encabezado If-Modified-Since en la solicitud y analice la fecha (si existe).
  • Compárelo con la fecha de la última modificación de su imagen original (generada dinámicamente). Rastrear esto es probablemente la parte más compleja de la solución a este problema. En su situación actual, está recreando la imagen en cada solicitud; No quieres hacer eso a menos que sea absolutamente necesario.
  • Si la fecha del archivo que tiene el navegador es más nueva o igual a la que tiene para la imagen, envíe un 304 No modificado.
  • De lo contrario, continúa con tu implementación actual.

Una forma sencilla de realizar un seguimiento de los últimos tiempos modificados en su extremo es almacenar en caché las imágenes recién generadas en el sistema de archivos y mantener un diccionario en la memoria que mapea la identificación de la imagen a una estructura que contiene el nombre del archivo en el disco y la fecha de la última modificación. Utilice Response.WriteFile para enviar los datos desde el disco. Por supuesto, cada vez que reinicies el proceso de trabajo, el diccionario estará vacío, pero obtendrás al menos algún beneficio de almacenamiento en caché sin tener que lidiar con la información de almacenamiento en caché persistente en algún lugar.

Puede apoyar este enfoque separando las preocupaciones de "Generación de imagen" y "Envío de imágenes a través de HTTP" en diferentes clases. Ahora mismo estás haciendo dos cosas muy diferentes en el mismo lugar.

Sé que esto puede sonar un poco complejo, pero vale la pena. Recientemente implementé este enfoque y los ahorros en tiempo de procesamiento y uso de ancho de banda fueron increíbles.


Así es como se hace en Roadkill''s controlador de archivos de Roadkill''s (un wiki de .NET):

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;

La respuesta de Thomas acerca de que IIS no proporciona el código de estado es la clave, sin eso, solo obtendrás 200 cada vez.

El navegador simplemente le enviará una fecha y hora para cuando piense que el archivo se modificó por última vez (no hay ningún encabezado), por lo que si difiere, simplemente devuelva 200. Es necesario normalizar la fecha de su archivo para eliminar milisegundos y asegurarse Es una fecha UTC.

He pasado a los valores predeterminados a 304 si hay una versión modificada válida desde entonces, pero se puede modificar si es necesario.


Si tiene un archivo fuente en el disco, puede usar este código:

context.Response.AddFileDependency(pathImageSource); context.Response.Cache.SetETagFromFileDependencies(); context.Response.Cache.SetLastModifiedFromFileDependencies(); context.Response.Cache.SetCacheability(HttpCacheability.Public);

Además, asegúrese de probar con IIS, no desde Visual Studio. El servidor de desarrollo ASP.NET (también conocido como Cassini) siempre establece el control de caché en privado.

Ver también: Tutorial de almacenamiento en caché para autores web y webmasters