Pull to refresh

Comments 14

Это — хорошее пособие для новичков, на деле «просто» все-равно не получится, потому что инвалидация кеша в некоторых ситуациях сопровождается баттхертом. Вы привели отличную цитату Арта Тейлора, я приведу другую:

There are only two hard things in Computer Science: cache invalidation and naming things.

— Phil Karlton

за эту цитату спасибо ( habrahabr.ru/users/zerkms/, если хабр порежет юзер-тэг, — не знаю с чем связано, у меня Хабр частенько тэги режет)
Простите, я что-то не понял:
>Если запрос не вернет записей, отправляем 304 Not Modified. Таким образом, если у пользователя 300 друзей и только двое из них были добавлены недавно, то ответ будет содержать только две записи.

Насколько я понимаю, если есть изменения после IF-MODIFIED-SINCE — нужно прислать обновленный объект (список друзей), а не разницу. Так как решается вопрос инвалидации имеющегося у клиента кэша, таким образом, если объект на сервере изменен — это не проблемы клиента как именно он изменился, ему нужен актуальный объект. Или здесь какая-то хитрая RESTful API собака зарыта?
Если на клиенте есть список из 298 друзей, то докачиваем 2 недостающих. Видимо так.
Я уточню вопрос — представим себе абстрактное клиентское приложение делающее запросы:
No cache version: запрос http://api.mynextfacebook.com/friends/ -> 200 OK -> 298 друзей
IF-MODIFIED-SINCE=10: запрос http://api.mynextfacebook.com/friends/ -> 304 Not Modified
... произошло добавление двух друзей ...
IF-MODIFIED-SINCE=20: запрос http://api.mynextfacebook.com/friends/ -> 200 OK -> 2 друга
IF-MODIFIED-SINCE=30: запрос http://api.mynextfacebook.com/friends/ -> 304 Not Modified


Цифры 10, 20, 30 — взяты для примера, думаю что всем понятно что там должен быть честный timestamp.

Получая такие ответы от сервера приложение должно merge имеющего кэша и нового ответа, результат этого merge оно должно закэшировать и именного его использовать. Но при этом отличить ответ — это полный объект или только обновление при кэшировании можно только по заголовкам.

Но при использовании какого-нибудь network framework'a приложение ожидая ответ от сервера на запрос списка друзей получает совершенно не то:
— приложение может и знать-не-знать про кэширование — так как эту задачу на себя берет framework, следовательно оно не обязано знать что до такого-то момента у пользователя было 298 друзей;
— network framework — совершенно не обязан делать merge кэша и результата нового запроса, так как его задача получить данные, а что они из себя представляют JSON/XML/XHTML — это не его головная боль, следовательно не его дело менять данные ответа от сервера.

Таким образом получается что для работы такого поведения сервера клиентское приложение должно хранить 2 версии кэша — network framework, для того чтобы работать по rfc2616, + приложение должно знать о том какое было состояние до запроса, чтобы вычислить текущее положение дел (сделать merge). А если добавить к этому то что приложение вынужденно знать использовался ли кэш или нет (чтобы понять как обрабатывать ответ — добавлять 2 друзей или список состоит из 2-х друзей) — возникает вопрос network framework получается нужен чтобы сокет открыть и пописать+почитать в/из него? Network framework используют как-раз с целью избавить приложение от необходимости работать с сетью. И как cherry-on-top вспомним то, что кэш — субстанция которая может быть удалена разными механизмами и далеко не все из них удосужатся сообщить приложению об удалении его кэша.

Таким образо либо я что-то не понял из статьи, либо что-то очень хитрое придумал, либо тут все-таки RESTful API собака зарыта.

P.S. под network framework — понимаются например MKNetworkKit или иной, которому для работы нужно лишь сказать куда класть кэш и можно начинать делать запросы.
Когда есть IF-MODIFIED-SINCE, тогда присылается только разница (2 новых друга из примера).
Когда нужен полный список просто не отправляем заголовок IF-MODIFIED-SINCE (что в принципе тоже самое, что послать 0). АРІ должен вернуть полный набор.
Простите, но как приложение поймет что ответ является только разницей, а не полным набором, если оно использует фреймворк для работы с сетью/http, а не само рулит кэшированием? Ведь в этом случае оно не знает какие были использованы заголовки, а исходя из статьи выходит что формат ответа будет идентичен, за исключением кол-ва элементов, что не может быть достоверным признаком для определения типа ответа (обновление или полные данные).
Тогда автору следует ознакомиться с RFC 2616:

If the variant has been modified since the If-Modified-Since
date, the response is exactly the same as for a normal GET.


Можно было бы придумать что-то с RANGE, но как тогда быть с удаленными и измененными данными не ясно.
Немного некрофилия, конечно.

Если хочется реализовать пересылку диффов (съэкономить на пересылке больших списков), то есть следующий подход:
— делаем два метода: /friends и /friends/diff
— оба принимают If-Modified-Since
— первый метод (/friends) при наличии изменений в списке друзей высылает обновленный список полностью (как и без заголовка If-Modified-Since) или отдаёт HTTP 304 (если изменений не было)
— второй метод (/friends/diff) при наличии изменений высылает структурированный разностный документ (с полями added и deleted, например) или отдаёт HTTP 304 (если изменений не было).

Вариант, описанный в статье, является опасной ересью (возможно, что просто в силу упрощения) и может дать сложно-диагностируемые проблемы. Например, при использовании какого-нибудь REST-framework, который сам управляет кэшированием.
Имхо, в постах подобного типа «некрофилия» более чем уместна, тем более с таким шикарным разруливанием достаточно распространённой ситуации. Отдельное спасибо за сам trick )
Всегда пожалуйста =)

Сам всегда радуюсь, находя в комментариях полезные сведения. Иногда даже оказываются полезнее самой статьи.
IF-MODIFIED-SINCE и IF-NONE-MATCH при отсутсвии изменений присылают 304, при наличии — новый объект целиком, который в свою очередь кешируется и используется дальше
Для понимания и написания REST API очень хорошо подходит Webmachine, там всё по полочкам разложено.
Правда она на эрланге. Может есть аналоги и на другие языки?
Sign up to leave a comment.

Articles