2012-08-07 16 views
6

chciałbym realizować następujące funkcje:Jak pobrać obraz z HTTP tylko, jeśli obraz jest nowszy?

  1. C# klient łączy się z serwerem HTTP i pobiera obraz na dysku.

  2. Następnym razem, gdy klient rozpocznie sprawdzanie, czy obraz na serwerze jest nowszy niż obraz na dysku, w takim przypadku klient zastępuje obraz na dysku.

Dla mnie łatwo jest pobrać obraz, ale nie wiem, jak sprawdzić, czy obraz na serwerze jest nowszy. Jak mogę to wdrożyć? Sądzę, że mógłbym sprawdzić znacznik czasu lub rozmiar obrazu (lub oba), ale nie wiem, jak to zrobić.

+0

To może Cię zainteresować: https://developers.google.com/speed/docs/best-practices/caching#LeverageBrowserCaching – rboarman

+1

Czy masz kontrolę nad serwerem sieciowym? Jeśli nie, czy obsługuje buforowanie, Etagi, ... podczas serwowania tych obrazów? –

+0

Nie wiem, jak to działałoby za pośrednictwem protokołu HTTP, ale można wypróbować [właściwość FileInfo's CreationTime] (http://msdn.microsoft.com/en-us/library/system.io.filesysteminfo.creationtime.aspx). Powód, dla którego nie jestem pewien, to to, że nie mogę stwierdzić, czy wartość nieruchomości byłaby faktyczną datą utworzenia lub czy byłaby to data, w której byłeś ostatni (jestem trochę nieświadomy tego tematu). Warto się przyjrzeć. – MilkyWayJoe

Odpowiedz

5

HttpWebRequest może po prostu użyć cache IE, więc jeśli wszystkie obrazy będą w tym cache tak, a koszt ponownego pisania pliku (ale nie trzeba go pobrać) jest dopuszczalne, można po prostu zrobić wykorzystanie tego.

Jeśli trzeba obsłużyć się jednak wówczas:

Dane:

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. 

Będziesz musiał przechowywać je pod koniec tego i odzyskać je ponownie (jeśli nie jest nowy image) na początku.To zależy od ciebie, biorąc pod uwagę, że reszta działa:

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-znaczniki są bardziej niezawodne niż w ubiegłym modyfikowany gdy realizowane prawidłowo (zauważając sub-sekundowe uchwał w sprawie zmian i odzwierciedlające różne reakcje ze względu na różne Accept- * nagłówki). Niektóre implementacje są jednak błędne (IIS6 na farmie sieciowej bez konkretnej poprawki, Apache z mod-gzip), więc warto wydobyć kod związany z e-tagami i po prostu mijać datę.

Edycja: Jeśli chciałbyś pójść jeszcze dalej w implementacji buforowania HTTP, możesz również zapisać wygasanie i maksymalny wiek (użyj tych ostatnich, jeśli oba są obecne i nie zgadzają się z poprzednim) i pomiń pobieranie całkowicie, jeśli jest wcześniej, niż sugerują te wartości. Zrobiłem to i działa dobrze (miałem pamięć podręczną w pamięci obiektów utworzonych przez XML zwrócony przez różne URI, a jeśli XML był świeży lub nie został zmieniony, ponownie użyłem obiektu), ale może to być nieistotne dla twoich potrzeb (jeśli chcesz być odświeżony, niż sugeruje serwer, lub jeśli zawsze będziesz poza tym oknem).

6

Wypróbuj If-Modified-Since pole żądania. http://en.wikipedia.org/wiki/List_of_HTTP_header_fields Nie jestem pewien, czy jest w pełni obsługiwany przez każdy serwer. Więc jeśli nie jest on obsługiwany i nadal otrzymasz plik (a nie 304, jeśli jest obsługiwany), możesz obliczyć sumy kontrolne i jeśli są one różne, rozważ zmodyfikowany plik. Lub po prostu zastąp - i zawsze będziesz mieć najnowszą wersję.

+0

Serwery, które jej nie obsługują są rzadkie. Czasem zdarza się, że nie jest obsługiwany dla każdego zasobu (np. Strony ASP.NET lub PHP nie są domyślnie, ponieważ wymaga to logiki, aby wiedzieć, jaka data ma zostać wysłana, ale z pewnością może ją wspierać), ale wszystkie serwery przynajmniej obsługują "Przepraszam, nie wiem, tu jest cała sprawa", zamiast dławić się tym. Kod, który podaję, wykorzystuje to, a także e-tagi. –

2

Należy przeczytać RFC 2616 i powiązane dokumenty RFC (wyszukaj numer 1616 pod numerem http://www.rfc-editor.org/cgi-bin/rfcsearch.pl). W szczególności interesujące jest § 13, Buforowanie w HTTP, strony 47 – 62. Następnie przeczytaj powiązane nagłówki żądań/odpowiedzi i powiązane kody statusu, które możesz odzyskać.

Otrzymujesz dostęp do wszystkich nagłówków i wartości stanu za pośrednictwem klas HttpWebRequest i .

Należy jednak pamiętać, że można poprosić serwer o dowolne urządzenie: ostatecznie to serwer decyduje, czy wysłać nową reprezentację tego identyfikatora URI, czy nie. Możesz użyć czasownika HTTP HEAD zamiast jego czasownika GET, aby przesłuchać serwer o zasobie.

Metoda HEAD jest identyczna z GET wyjątkiem tego, że serwer nie musi zwracać wiadomość-ciało w odpowiedzi. Metainformacja zawarta w nagłówkach HTTP w odpowiedzi na żądanie HEAD POWINNA być identyczna z informacją przesłaną w odpowiedzi na żądanie GET w postaci . Ta metoda może być użyta do uzyskania metainformacji o jednostce implikowanej przez żądanie bez przenoszenia samej jednostki-podmiotu. Ta metoda jest często używana do testowania łączy hipertekstowych pod kątem poprawności, dostępności, i ostatniej modyfikacji.

+0

Jakiego wykorzystania przy wysyłaniu HEAD? Albo wyśle ​​304, w takim przypadku jest to to samo, co GET, albo wyśle ​​200, w takim przypadku jedynym sposobem, by się upewnić, jest wydanie GET po tym. –

+0

HEAD nie zwróci ciała; GET może, ale nie musi. HEAD pozwoli ci unieważnić buforowany element bez pobierania nowej reprezentacji. W zależności od wymagań preferowanym zachowaniem może być odroczenie dodania nowej reprezentacji do pamięci podręcznej. W związku z tym warunkowa "** siła **" w mojej odpowiedzi. –

+0

Ale w przypadku, gdy HEAD zwraca wartość 200, możemy być pewni, że zdecydowanie chcemy uzyskać GET (inna długość treści), ale nie, że na pewno nie będziemy (jeśli mają tę samą długość treści, mogą być nadal różne obrazy), więc i tak musimy to zrobić. Jedyną możliwością jest to, że ktoś wysyła nagłówki MD5 i nie wysyła ostatnich tagów lub e-tagów, co jest technicznie możliwe, ale na tyle perwersyjne, że taka osoba zasługuje na klapsa i jest mało prawdopodobna w prawdziwym życiu (nagłówki MD5 są rzadkie, ostatnie -mod i e-tagi są domyślnym zachowaniem dla "plików statycznych" na prawie wszystkich serwerach, a czasami poza nimi). –