Это должно быть довольно просто ... как это часто бывает ...
Я пишу настольное приложение на Java, которое должно хранить кеш изображений из Facebook.
Кажется, я не могу точно определить, когда произошел сбой или пропуск кэша, как я ожидал бы, основываясь на дате модификации ресурса.
Я заметил, что заголовок last-modified
в ответах Facebook почти всегда (в случае изображений профиля, полученных методом, описанным ниже) полуночи 1 января 2009 года ... Просматривая несколько страниц на сайте с Монитор ресурсов Chrome открыт, я вижу, что на многих изображениях эта дата действительно установлена как последняя измененная, и что в случаях, когда это верно, они также, по крайней мере, имеют значение X-Backend
, X-Blockid
& X-Cache-by
(или иногда X-N
) полей. Есть и другие случаи, когда last-modified
установлена на более старую дату, а X-*
нет, и другие перестановки тоже (в основном это похоже на интерфейс и рекламную графику).
Пока что поиск информации по этим x-*
заголовкам в сочетании с ограниченным базовым знанием HTTP оставил мне немного мудрее в том, как правильно реализовать мой кеш. Очевидно, что между обычным браузером и серверами Facebook нет проблем с установлением актуальности изображений в кеше, но мне не ясно, какой механизм используется для этого.
На данный момент у меня есть метод, который открывает URLConnection
для соответствующего ресурса facebook, устанавливая ifmodifiedsince
в тех случаях, когда в кэше уже существует соответствующий файл. Если я получу код ответа 304, тогда я вернусь - после вызова setLastModified
для файла кэша для хорошей меры (отчасти потому, что на данный момент кэш изображений собирается в SVN, и им всем присваивается значение lastModified всякий раз, когда они происходят с проверить).
public static void downloadPicture(String uid) {
try {
URL url = new URL("http://graph.facebook.com/" + uid + "/picture?type=large");
String fileName = "data/images/" + uid + ".jpg";
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
File cachedPic = new File(fileName);
long lastModified = cachedPic.lastModified();
if (cachedPic.exists()) {
conn.setIfModifiedSince(lastModified);
}
conn.connect();
if (conn.getResponseCode() == 304) {
System.out.println("Using cache for " + uid);
cachedPic.setLastModified(conn.getLastModified());
return;
}
System.out.println("Downloading new for " + uid);
ReadableByteChannel rbc = Channels.newChannel(conn.getInputStream());
FileOutputStream fos = new FileOutputStream(fileName);
fos.getChannel().transferFrom(rbc, 0, 1 << 24);
fos.close();
} catch (MalformedURLException e) {
System.err.println("This really shouldn't happen...");
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Несомненно, есть и другие улучшения, которые необходимо внести в способ, которым я выполняю этот процесс (приведенный выше код отнимает значительное количество времени для каждого отдельного элемента, чего он явно не должен, и я уверен, что смогу решить - хотя комментарии по наилучшей практике все еще приветствуются), но мне нужно выяснить, почему я, кажется, всегда получаю 304, когда присутствует какой-либо кэшированный файл, и каков правильный метод для обеспечения отправки правильных запросов.