Правильное REST кэширование

    Пусть мы хотим написать свой хабрахабр с блекджеком и прочими прелестями. Страница статьи у нас стостоит из 3 объёмных блоков:
    1. собственно текст статьи. меняется очень редко.
    2. дерево комментариев. меняется относительно часто, но со временем всё реже и реже.
    3. прямой эфир. небольшой, но меняется очень часто.

    Допустим, что страница с этой статьёй доступна по адресу ?article:right.cache
    Но внутрь неё мы не будем помещать никакого контента, а вынесем его в отдельные ресурсы, как это обычно делается со скриптами и стилями. Внутри ?article:right.cache будет лишь индекс подключаемых ресурсов с версиями.

    ?article:right.cache/content/version:123
    ?article:right.cache/comments/time:2010-12-01
    ?live/time:2010-12-01
    ?style:article/version:666
    ?script:article/version:333

    Указание версии позволяет задать для ресурсов жёсткое кэширование. А для индексного файла, наоборот, зададим необходимость проверять при каждом запросе изменился ли он.

    Такая организация гарантирует нам, что при появлении новых комментариев не придётся грузить статью заново. И наоборот, при изменении статьи не надо будет перегружать всё дерево комментариев. А уж про то, что из-за часто меняющегося прямого эфира нам не надо по новой грузить весь контент, и заикаться не стоит ;-)

    Важно, чтобы поисковики видели ссылки на ресурсы и могли их проиндексировать. Однако, из поиска люди будут приходить на конкретный ресурс и даже на конкретную его версию. Соответственно, ресурс должен определять загружен ли он по прямой ссылке и если это так, то после загрузки клиентскими средствами редиректить на индекс. Если актуальная версия ресурса не изменилась, то он потом будет взят из кэша. Если же изменилась — будет загружена новая версия. Не такая уж страшная беда, на самом деле ;-)

    Реализации с использованием фреймов и аякса довольно банальны, так что воспользуемся хтмл-инклудами.

    Индекс не представляет из себя ничего нового.

    <!DOCTYPE t:stylesheet [ <!ATTLIST t:stylesheet id ID #REQUIRED> ]><br><?xml-stylesheet type="text/xsl" href="#t:stylesheet"?><br><t:stylesheet id="t:stylesheet" version="1.0" xmlns:t="http://www.w3.org/1999/XSL/Transform"><br>    <t:output doctype-public="-//W3C//DTD XHTML 2.0//EN" doctype-system="http://www.w3.org/MarkUp/DTD/xhtml2.dtd" /><br>    <t:template match=" @* | node() "><br>        <t:copy><br>            <t:apply-templates select=" @* | node() " /><br>        </t:copy><br>    </t:template><br>    <t:template match=" *[ @src and contains( @srctype, 'xml' ) ] "><br>        <t:copy><br>            <t:apply-templates select=" @* " /><br>            <t:apply-templates select=' document( @src )//html/body/* ' /><br>        </t:copy><br>    </t:template><br>    <t:template match=" / "><br>        <t:apply-templates select=" document( '#t:stylesheet' )//html " /><br>    </t:template><br>    <t:template name="content"><br>        <html><br>         <head><br>            <title>Article with comments</title><br>            <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><br>            <link href="?style:article/version:666" type="text/css" rel="stylesheet" /><br>            <script src="?script:article/version:333" type="text/javascript"></script><br>         </head><br>         <body><br>             <section src="?article:right.cache/content/version:123" srctype="text/xml"><br>                 <a href="?article:right.cache/content/version:123">article content</a><br>             </section><br>             <section src="?article:right.cache/comments/time:2010-12-01" srctype="text/xml"><br>                 <a href="?article:right.cache/comments/time:2010-12-01">article comments</a><br>             </section><br>             <section src="?live/time:2010-12-01" srctype="text/xml"><br>                 <a href="?live/time:2010-12-01">live content</a><br>             </section><br>         </body><br>        </html><br>    </t:template><br></t:stylesheet>


    А вот у ресурса будут другие шаблоны.

    <!DOCTYPE t:stylesheet [ <!ATTLIST t:stylesheet id ID #REQUIRED> ]><br><?xml-stylesheet type="text/xsl" href="#t:stylesheet"?><br><t:stylesheet id="t:stylesheet" version="1.0" xmlns:t="http://www.w3.org/1999/XSL/Transform"><br>    <t:output doctype-public="-//W3C//DTD XHTML 2.0//EN" doctype-system="http://www.w3.org/MarkUp/DTD/xhtml2.dtd" /><br>    <t:template name="content"><br>        <html><br>            <head><br>                <title>Article content</title><br>                <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><br>            </head><br>            <body><br>                <h>Article content</h><br>            </body><br>        </html><br>    </t:template><br>    <t:template match=" / "><br>        <t:element name="meta"><br>            <t:attribute name="http-equiv">refresh</attribute><br>            <t:attribute name="content">0;url=?article:right.cache</attribute><br>        </t:element><br>    </t:template><br></t:stylesheet>

    При прямом запросе браузером произойдёт редирект на ?article:right.cache
    Поисковик же получит контент и проиндексирует его.
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 43
    • +3
      Спасибо за статью.

      >>Поисковик же получит контент и проиндексирует его.
      Но не так, как было бы с обычной страницей. Нужно исследование как это влияет на выдачу.
      • 0
        конечно, но это к сожалению не мой профиль ._.
        • +1
          Про этот вариант ничего не скажу — не использовал такое. А обычный xHTML+XSLT роботы кушают хорошо. И даже лучше чем обычные страницы. Потому что XSLT позволяет реализовать 100% и валидный noindex.
          • +1
            кастомный доктайп тоже это может ;-)
            • +2
              Я не знаю каким образом поисковики определяют что есть HTML, а что XSLT и насколько важно для них то, что они определили. Вполне допускаю, что есть какие-нибудь нюансы.
              Я вообще очень удивился, когда обнаружил, что goolge XSLT-файл из xml-stylesheet сожрал и проиндексировал. Яндекс, естественно, его проигнорировал.
              • 0
                покажи его о_0"
                • +2
                  Задача была именно что скрыть XSLT.
                  Я делаю через него include того, что робот не должен видеть. Но фокус не удался.
                  • 0
                    а точно делаешь? просто я пооткрывал твои сайты в хроме и не нашёл там упоминания об xslt
                    • +3
                      Фича такая. Хром в исходниках дает не исходник, а результат преобразования.
                      Я когда эти сайты делал хрома не было. На одном из них вообще в хроме подвал перекошен.
                      У меня есть глубокомысленный личный проект на нескольких доменах с 15.000 посещаемостью и почти 10 летней историей. Модернизация давно назрела. Потихоньку делаю. Вот все думаю сделать — не сделать на XSLT-клиент.
                      Хочется, но больно геморойно и никак не справлюсь с DOCTYPE.
                      Декларативно все генерируют правильно. По факту — квиркмод
                      • +1
                        а что там сложного с доктайпом?
                        • +1
                          Парсится все как будто квиркмод выставлен, а не xHTML, который я задал.
      • +2
        При прямом запросе браузером произойдёт редирект на ?article:right.cache
        Поисковик же получит контент и проиндексирует его.

        Я конечно не большой специалист в SEO, но разве это не будет считаться клоакингом, со всеми вытекающими?
        • +2
          нет
          • +2
            Эт хорошо. Хоть и не мой профиль, но статья интересная, спасибо.
          • +2
            Это не более чем технический прием. Если в с его помощью будете спамить и клоачить — это будет считаться спамом и клоакингом, если нет — не будет.
            Но в отличие от традиционных способов клоакинга — этот поисковики опредить не могут. Только по стуку.
          • +1
            вопрос на засыпку: при чем здесь клиентская оптимизация? :)
            • +2
              да, ответ глубоко зарыт
              habrahabr.ru/blogs/xslt/90373/#comment_2720218

              имхо, технология интересная, но тупиковая: размер HTML сейчас нисколько не критичен (после автоматического gzip/minify), а вот скорость разбора документа на клиенте весьма и весьма важна…
              • 0
                не знаю насколько он не критичен, но при обновлении страницы со статьёй на хабре я вижу как она очень постепенно загружается в течении 3 секунд на 10 мегабитах.
                • +2
                  я, конечно, извиняюсь, но загружается она так медленно из-за
                  (1) большого количества рекламных вызовов «там-сям»
                  (2) из-за бардака в клиентской оптимизации (количество файлов легко можно вдвое уменьшить)

                  Данный подход конкретно для Хабра сделает только хуже
                • 0
                  >размер HTML сейчас нисколько не критичен
                  Ну да у всех же безлимит 100Мбит.
                  >а вот скорость разбора документа на клиенте весьма и весьма важна…
                  Не замерял. Честно признаюсь. Хотя надо было бы.
                  Визуально (если не парсить все дерево, а только переставлять и подтягивать блоки) все выполняется достаточно быстро, задержка незаметна. Что достаточно важно — все блоки появляются одновременно, а не как с include через Ajax. Даже если по времени это было бы дольше, чисто психологически — задержка не так заметна как в случае с постепенным появлением контента.

                  • +1
                    >>размер HTML сейчас нисколько не критичен
                    > Ну да у всех же безлимит 100Мбит.

                    Извините, но Вы сейчас чушь сказали :) Посчитайте, сколько пользователь теряет
                    1) На загрузке сжатого и архивированного HTML
                    2) На загрузке всех остальных (пусть и оптимизированных) компонентов страницы
                    3) На осуществлении 3-5 дополнительных запросов к серверу, которые не уменьшают размер HTML

                    И лучше это делать для пинга не в 1 мс :) Потому что в этом случае у пользователей, скорее всего, 100Мбит

                    • +1
                      > Не замерял. Честно признаюсь. Хотя надо было бы.

                      Замерьте. И не на двухядерном Xeon, а на каком-нибудь нетбуке. Все будет куда менее очевидно :)

                      Хотя интереснее это будет сравнить со скоростью загрузки этих же элементов в iframe. Мне кажется, что разброс будет в районе 10-20%.
                      • 0
                        Смысл применения этой технологии в том, чтобы один раз скачанный блок кешировался и больше не грузился. Т.е. Мы теряем при первой загрузке страницы, зато при повторных мы выигрываем.
                        Насчёт разницы в скорости отрисовки спорить без тестов, и тем более приводить какие то числа-немного странно, имхо. Но могу сказать что у xslt неплохие шансы, потому что эту технологию разрабатывает w3c и она в плане быстродействия очень неплоха.
                        • +1
                          имхо
                          1) Реализация обновления страницы на уровне браузера убивает, как минимум, 50% выигрыша. Все «сэнономленные» запросы будут вновь и вновь уходить-приходить (новая вкладка, Ctrl+R, что-то еще браузеру не понравится). Я не вижу здесь какой «прорывной» составляющей: еще один (скорее всего) спорный подход к решению давней проблемы.
                          2) xslt тормозит. Везде: на клиенте и на сервере. Это аксиома такая :)
                          3) Говорить о том, что w3c разрабатывает xslt, и поэтому эта технология крута, — глупо. XHTML2 тоже w3c разрабатывает (или уже таки остановилось?), но это явно тупиковая ветвь. Таких полутупиковых (потому что они не мейнстрим, и часто применяются не по делу) технологий у w3c много (было бы странно, если бы такая крупная организация разрабатывала исключительно только мейнстрим :)

                          и, наконец,
                          4) экономить по 4-10 Кб на таких запросах (эта страница в сжатом виде (даже без minify) меньше 20 Кб занимает) — это уже совсем перекос. Лучше блокирующие скрипты пересобрать/вынести и стили нормальные написать (чтобы рендеринг не тормозил) — эффекта будет больше. Или картинки в спрайты / data:URI запихнуть. Или их поотимизировать. Или выкинуть лишнюю клиентскую логику (типа инициализации jQuery везде, где только можно).
                          • –1
                            1. именно для этого и используется жёсткое кэширование ресурсов.
                            2. глупость.
                            4. 20кб через жопорез — это не так уж и мало.
                            • +1
                              2) xslt тормозит. Везде: на клиенте и на сервере. Это аксиома такая :)
                              На клиенте я не знаю не замерял. А на сервере скажу — операция финишной сборки (у меня) занимает 2-5 мсек. На локальном серевере (слабенький ноутбук) 5-10 мсек.
                              Я понимаю, что у броузеров парсеры сильно-сильно тормозные, но не настолько же.
                              4) Если верить данным li.ru на среднем новостном сайте соотношение хитов/хостам 1:10
                              10K*10 хитов = 100

                              Я с вами согласен в п.2 клиентский XSLT, скорее всего тупиковая вещь. За десять лет я не вижу никаких подвижек в эту строну. И вряд ли увижу дальше.

                              • 0
                                в браузерах совсем не тормозные: libxslt, msxml, transformiix
                  • +1
                    Статья — понятно. Комменты — понятно. А что за «прямой эфир»?
                    • +1
                      справа от этой статьи посмотрите :)
                      • +2
                        Справа от статьи у болшой прямоугольник, в котором написано «click here to download plugin» :-)
                          • +2
                            Во оно как, оказывается я.директ еще там висит, вот так на чужих скринах и узнаешь как должна выглядить страница без адблокеров )))
                    • 0
                      Интересная идея, но заморочная имхо, и вообще непривычны все эти инклюды, наверно лучше внутри сервера все же собирать страницу из (возможно) кешированных кусочков. Идея с использованием номера версии/даты обновления интересная.
                      • 0
                        Тут смысл в клиентском кешировании больших блоков.
                        Например, у вас на сайте есть объемный сайд бар (или большое левое меню как на alibaba.com)
                        В таком случае не имеет смысла заставлять пользователя каждый раз его перекачивать, проще 1 раз ему отдать этот сайдбар чтобы он закешировался.

                        Идея с использованием ревизии/даты обновления довольно стандартная и часто используется для кеширования статики (изображений/цсс).

                        Работает она так: например у вас есть картинка сайт.ру/img/image.jpg
                        вы пишете рерайт правилос чтобы site.ru/img/r[0-9]*/image.jpg вело на /img/image.jpg, а саму image.jpg отдаете с сервера с заголовком expires на год вперед чтобы она у клиента закешировалась хорошо и надолго.
                        теперь при изменении изображения вам придется переписать ссылку на него везде где она есть на ссылку с новой ревизией (обычно это делается автоматически с помощью какой нибудь функции Template::getImageUrl('image.jpg'); которая проверяет ревизию файла и вставляет нужную ссылку), а у клиента соответсвенно браузер видит что изменился урл и перекачивает картинку, которую потом снова кеширует. Такой подход сопряжен с определенными сложностями — в частности, придется переписывать весь цсс чтобы там картинки вставлялись с помощью вашей функции.

                        Есть еще одна хитрость, которая позволяет облегчить работу с цсс — можно создавать домены третьего уровня вида r[0-9]*.site.ru, который будет просто альясом основного сайта (настраивается в dns один раз, не надо каждый раз создавать поддомены), и в шапке инклудится какой нибудь master.css с домена r123.site.ru, который уже подтягивает все другие css.
                        Смысл такого подхода в том, что другие цсс и картинки будут тянуться с того же домена, что и мастер.цсс, и следовательно для изменения ревизии достаточно в 1 месте — в шапке поменять домен и на клиентской машине обновится весь кеш разом.

                        Комбинирование этих двух подходов (поддомен для css и Rewrite для статики, которая вставляется на странице) позволяет хорошо кешировать статику сайта на клиентской машине, и с точки зрения разработчика этот кеш удобно обновлять.
                        • +1
                          как раз загрузка (конкретно) css с таких доменов — шаблон антиоптимизации. Ключевое слово — DNS.
                          Лучше просто реврайты, типа
                          main.wo123.css -> main.css
                          • 0
                            зачем нам лишние обращения к днс? лучше уж так: css.xxx.ru/123.css
                            • +1
                              css.xxx.ru — еще один шаблон антиоптимизации. DNS-запрос в первый раз не кэшируется, а потом он не нужен, потому что CSS закэширован :) В итоге каждый раз мы (если только CSS не раз в час меняется :) делаем доп. DNS-запрос для CSS-файла.
                              • 0
                                у тебя всё-равно будут лишние запросы к днс после каждого апдейта вёрстки
                                • +1
                                  не будут, если CSS на том же домене. 500 байтов cookie — ничто по сравнению с 1 DNS-запросом.
                                  • +1
                                    а, блин… я подумал, что main.wo123.css — это домен такой у тебя х)
                                • +1
                                  Просто реврайты такого типа добавляют сложности с тем, что надо искать все вхождения картинок в цсс и им прописывать новую ревизию, хотя это конечно можно автоматизировать каким нибудь скриптоп перед выкладыванием новой верстки на продакш. Способ с поддоменами хорош тем, что легко внедряется и требует относительно мало трудозатрат, при этом свою задачу выполняет исправно-кеширует цсс и картинки из цсс и позволяет быстро обновить всю верстку.
                                  Опять же, вынос изображений и цсс на поддомен плох тем, что создает лишний днс запрос, а хорош тем, что позволяет создать больше параллельных запросов с сервера ( актуально например в случае новостных лент с обилием изображений)
                                  • +1
                                    В WEBO Site SpeedUp это уже давно автоматизировано и работает на нескольких тысячах сайтов.

                                    CSS на отдельный поддомен выносить — зло! расстреливать за это нужно.

                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.