2012-08-07 12 views
6

me gustaría realizar las funciones siguientes:¿Cómo descargar imágenes de HTTP solo si la imagen es más reciente?

  1. A C# cliente se conecta a un servidor HTTP y descarga una imagen en el disco.

  2. La próxima vez que el cliente inicie las comprobaciones si la imagen en el servidor es más reciente que la imagen en el disco, y en este caso, el cliente reemplaza la imagen en el disco.

Para mí es fácil descargar la imagen, pero no estoy seguro de cómo comprobar si la imagen en el servidor es más reciente. ¿Cómo podría implementarlo? Supongo que podría verificar la marca de tiempo, o el tamaño de la imagen (o ambos), pero no sé cómo hacerlo.

+0

Esto puede ser de su interés: https://developers.google.com/speed/docs/best-practices/caching#LeverageBrowserCaching – rboarman

+1

¿Tiene control sobre el servidor web? Si no, ¿es compatible con el almacenamiento en caché, Etags, ... al servir esas imágenes? –

+0

No estoy seguro de cómo funcionaría esto a través de HTTP, pero podría probar [propiedad CreationTime de FileInfo] (http://msdn.microsoft.com/en-us/library/system.io.filesysteminfo.creationtime.aspx). La razón por la que no estoy seguro es que no puedo decir si el valor de la propiedad sería la fecha de creación real o si sería la fecha en que la accedió por última vez (soy un tanto ignorante sobre el tema). Vale la pena echar un vistazo aunque. – MilkyWayJoe

Respuesta

5

HttpWebRequest simplemente puede utilizar la caché de IE, por lo que si todas las imágenes estarán en esa caché de todos modos, y el costo de re-escribir el archivo (pero no tener que descargarlo) es aceptable, puede simplemente hacer uso de eso.

Si usted necesita para manejar por sí mismo, sin embargo, a continuación:

dado:

string uri; //URI of the image. 
DateTime? lastMod; // lastModification date of image previously recorded. Null if not known yet. 
string eTag; //eTag of image previously recorded. Null if not known yet. 

Vas a tener que almacenar estos al final de este, y recuperarlos de nuevo (cuando no una nueva imagen) al principio.Eso depende de usted, teniendo en cuenta que, el resto funciona:

var req = (HttpWebRequest)WebRequest.Create(uri); 
if(lastMod.HasValue) 
    req.IfModifiedSince = lastMod.Value;//note: must be UTC, use lastMod.Value.ToUniversalTime() if you store it somewhere that converts to localtime, like SQLServer does. 
if(eTag != null) 
    req.AddHeader("If-None-Match", eTag); 
try 
{ 
    using(var rsp = (HttpWebResponse)req.GetResponse()) 
    { 
    lastMod = rsp.LastModified; 
    if(lastMod.Year == 1)//wasn't sent. We're just going to have to download the whole thing next time to be sure. 
     lastMod = null; 
    eTag = rsp.GetResponseHeader("ETag");//will be null if absent. 
    using(var stm = rsp.GetResponseStream()) 
    { 
     //your code to save the stream here. 
    } 
    } 
} 
catch(WebException we) 
{ 
    var hrsp = we.Response as HttpWebResponse; 
    if(hrsp != null && hrsp.StatusCode == HttpStatusCode.NotModified) 
    { 
    //unfortunately, 304 when dealt with directly (rather than letting 
    //the IE cache be used automatically), is treated as an error. Which is a bit of 
    //a nuisance, but manageable. Note that if we weren't doing this manually, 
    //304s would be disguised to look like 200s to our code. 

    //update these, because possibly only one of them was the same. 
    lastMod = hrsp.LastModified; 
    if(lastMod.Year == 1)//wasn't sent. 
     lastMod = null; 
    eTag = hrsp.GetResponseHeader("ETag");//will be null if absent. 
    } 
    else //some other exception happened! 
    throw; //or other handling of your choosing 
} 

E-tags son más confiables que la última modificación, cuando se aplica correctamente (teniendo en cuenta las resoluciones inferiores a un segundo sobre los cambios, y que reflejan diferentes respuestas debido a la diferente Accept- * encabezados). Sin embargo, algunas implementaciones son problemáticas (IIS6 en una granja de servidores web sin un ajuste en particular, Apache con mod-gzip) por lo que puede valer la pena sacar el código relacionado con las etiquetas electrónicas y simplemente ir por la fecha.

Editar: Si quería ir más allá al implementar el almacenamiento en caché HTTP, también podía almacenar caducas y max-age (use este último si están ambos presentes y no está de acuerdo con el anterior) y omita la descarga por completo si es más temprano que esos valores sugieren. He hecho esto y funciona bien (tenía un caché en la memoria de objetos creados por el XML devuelto por varios URI, y si el XML era reciente o no había cambiado, volví a utilizar el objeto), pero puede ser irrelevante para sus necesidades (si desea estar más fresco de lo que sugiere el servidor, o si siempre estará fuera de esa ventana).

6

Pruebe If-Modified-Since campo de solicitud. http://en.wikipedia.org/wiki/List_of_HTTP_header_fields No estoy seguro de que sea totalmente compatible con todos los servidores. Entonces, si no es compatible y aún obtendrá el archivo (y no 304 si es compatible) puede calcular las sumas de comprobación y si son diferentes, considere la posibilidad de modificar el archivo. O simplemente sobrescriba, y siempre tendrá la versión más nueva.

+0

Los servidores que no lo admiten son raros. Algunas veces, no es compatible con todos los recursos (por ejemplo, las páginas ASP.NET o PHP no lo hacen de forma predeterminada, ya que requiere lógica para saber qué fecha enviar, aunque sin duda pueden respaldarlo), pero todos los servidores admiten al menos "lo siento, no sé, aquí está todo" en lugar de asfixiarse. El código que doy usa eso, y también etiquetas electrónicas. –

2

Necesita leer el RFC 2616 y RFCs relacionados (busque 1616 en http://www.rfc-editor.org/cgi-bin/rfcsearch.pl). En particular, § 13 es de interés, Almacenamiento en caché en HTTP, páginas 47 – 62. A continuación, lea los encabezados de solicitud/respuesta relacionados y los códigos de estado relacionados que pueda obtener.

Tiene acceso a todos los encabezados y valores de estado a través de las clases HttpWebRequest y HttpWebResponse.

Pero uno debe tener en cuenta que puede pedirle al servidor lo que quiera: en última instancia, es el servidor el que decide si le enviará una nueva representación de ese URI o no. Es posible que desee utilizar el verbo HTTP HEAD en lugar del verbo GET para interrogar al servidor sobre el recurso.

El método HEAD es idéntico a GET, excepto que el servidor NO DEBE devolver un cuerpo de mensaje en la respuesta. La metainformación contenida en los encabezados HTTP en respuesta a una solicitud HEAD DEBERÍA ser idéntica a la información enviada en en respuesta a una solicitud GET. Este método se puede usar para obtener metainformación sobre la entidad implícita en la solicitud sin transferir el cuerpo de la entidad en sí. Este método se usa a menudo para probar enlaces de hipertexto para validez, accesibilidad, y modificaciones recientes.

+0

¿De qué sirve enviar HEAD? O enviará un 304, en cuyo caso es lo mismo que GET, o enviará un 200, en cuyo caso la única forma de estar seguro es emitir un GET después de él. –

+0

HEAD no devolverá un cuerpo; GET podría o no podría. HEAD le permitirá invalidar el elemento en caché sin recuperar una nueva representación. Dependiendo de los requisitos, posponer el agregado de una nueva representación en la memoria caché puede ser el comportamiento preferido. Por lo tanto, el condicional '** might **' en mi respuesta. –

+0

Pero en el caso en que HEAD devuelva 200, posiblemente podamos saber que definitivamente queremos GET (diferente contenido-longitud) pero no que definitivamente no lo hagamos (si tienen la misma longitud de contenido, podrían ser diferentes imágenes), así que tenemos que OBTENER de todos modos. La única posibilidad es si alguien está enviando encabezados MD5 y no está enviando la última modificación o etiquetas electrónicas, lo cual es técnicamente posible, pero lo suficientemente perverso como para merecer una bofetada y poco probable en la vida real (los encabezados MD5 son raros, último -mod y e-tags son comportamientos predeterminados para "archivos estáticos" en casi todos los servidores, y algunas veces más allá de eso). –

Cuestiones relacionadas