1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
---
title: HTTP-кеширование
slug: Web/HTTP/Caching
tags:
- HTTP
- Кеширование
- Кеширование
- Руководство
translation_of: Web/HTTP/Caching
original_slug: Web/HTTP/Кеширование
---
<div>{{HTTPSidebar}}</div>
<p><strong>Производительность веб-сайтов и приложений можно значительно повысить за счёт повторного использования ранее полученных ресурсов. Веб-кеши сокращают задержку и снижают сетевой трафик, уменьшая тем самым время, необходимое для отображения ресурсов. Используя HTTP-кеширование, сайты становятся более отзывчивыми.</strong></p>
<h2 id="Различные_виды_кеширования">Различные виды кеширования</h2>
<p>Техника кеширования заключается в сохранении копии полученного ресурса для возврата этой копии в ответ на дальнейшие запросы. Запрос на ресурс, уже имеющийся в веб-кеше, перехватывается, и вместо обращения к исходному серверу выполняется загрузка копии из кеша. Таким образом снижается нагрузка на сервер, которому не приходится самому обслуживать всех клиентов, и повышается производительность — кеш ближе к клиенту и ресурс передаётся быстрее. Кеширование является основным источником повышения производительности веб-сайтов. Однако, кеш надо правильно сконфигурировать: ресурсы редко остаются неизменными, так что копию требуется хранить только до того момента, как ресурс изменился, но не дольше.</p>
<p>Существует несколько видов кешей, которые можно разделить на две основные категории: приватные кеши и кеши совместного использования. В кешах совместного использования (shared cache) хранятся копии, которые могут направляться разным пользователям. Приватный кеш (private cache) предназначен для отдельного пользователя. Здесь будет говориться в основном о кешах браузеров и прокси, но существуют также кеши шлюзов, CDN, реверсные прокси кеши и балансировщики нагрузки, разворачиваемые на серверах для повышения надёжности, производительности и масштабируемости веб-сайтов и веб-приложений.</p>
<p><br>
<br>
</p>
<p><img alt="What a cache provide, advantages/disadvantages of shared/private caches." src="https://mdn.mozillademos.org/files/13777/HTTPCachtType.png" style="height: 573px; width: 910px;"></p>
<h3 id="Приватный_private_кеш_браузера">Приватный (private) кеш браузера</h3>
<p>Приватный кеш предназначен для отдельного пользователя. Вы, возможно, уже видели параметры кеширования в настройках своего браузера. Кеш браузера содержит все документы, загруженные пользователем по HTTP. Он используется для доступа к ранее загруженным страницам при навигации назад/вперёд, позволяет сохранять страницы, или просматривать их код, не обращаясь лишний раз к серверу. Кроме того, кеш полезен при отключении от сети.</p>
<h3 id="Общий_shared_прокси-кеш">Общий (shared) прокси-кеш</h3>
<p>Кеш совместного использования — это кеш, который сохраняет ответы, чтобы их потом могли использовать разные пользователи. Например, в локальной сети вашего провайдера или компании, может быть установлен прокси, обслуживающий множество пользователей, чтобы можно было повторно использовать популярные ресурсы, сокращая тем самым сетевой трафик и время ожидания.</p>
<h2 id="Цели_кеширования">Цели кеширования</h2>
<p>Кеширование в HTTP не является обязательным, однако в большинстве случаев бывает полезно повторно использовать ранее сохранённые ресурсы. Тем не менее, стандартные кеши HTTP обычно способны кешировать только ответы на запросы методом {{HTTPMethod("GET")}}, а другие отклоняют.</p>
<p>Первичный ключ состоит из метода запроса и запрашиваемого URI (зачастую используется только URI, поскольку целью кеширования являются только GET-запросы). Вот примеры того, что обычно записывается в кеш:</p>
<ul>
<li>Успешно загруженные ресурсы: ответ {{HTTPStatus(200)}} <code>OK</code> на запрос методом {{HTTPMethod("GET")}} HTML-документов, изображений или файлов.</li>
<li>Постоянные перенаправления: ответ {{HTTPStatus (301)}} <code>Moved Permanently</code> («перемещено навсегда»).</li>
<li>Сообщения об ошибках: ответ {{HTTPStatus(404)}} <code>Not Found</code> («не найдено»).</li>
<li>Неполные результаты: ответ {{HTTPStatus(206)}} <code>Partial Content</code> («частичное содержимое»).</li>
<li>
<p>Ответы на запросы отличные от {{HTTPMethod("GET")}}, если есть что-либо, подходящее для использования в качестве ключа кеша.</p>
</li>
</ul>
<p>Запись в кеше может также состоять из множества ответов, различаемых по вторичному ключу, если при формировании ответа производится согласование данных. Подробнее об этом рассказано <a href="#Varying_responses">ниже</a>, в разделе, посвящённом заголовку {{HTTPHeader("Vary")}}.</p>
<h2 id="Управление_кешированием"><span class="long_text short_text" id="result_box" lang="ru"><span>Управление</span> </span>кеш<span class="long_text short_text" lang="ru"><span>ированием</span></span></h2>
<h3 id="Заголовок_Cache-control">Заголовок <code>Cache-control</code></h3>
<p>Поле {{HTTPHeader("Cache-Control")}} общего заголовка HTTP/1.1 используется для задания инструкций по механизму кеширования как в запросах, так и в ответах. Применяется для задания политик кеширования.</p>
<h4 id="Полное_отсутствие_кеширования">Полное отсутствие кеширования</h4>
<p>В кеше не должно сохраняться ничего — ни по запросам клиента, ни по ответам сервера. Запрос всегда отправляется на сервер, ответ всегда загружается полностью.</p>
<pre class="notranslate">Cache-Control: no-store
Cache-Control: no-cache, no-store, must-revalidate
</pre>
<h4 id="Кешировать_но_проверять_актуальность">Кешировать, но проверять актуальность</h4>
<p>Перед тем, как выдать копию, кеш запрашивает исходный сервер на предмет актуальности ресурса.</p>
<pre class="notranslate">Cache-Control: no-cache</pre>
<h4 id="Приватные_private_и_общие_public_кеши">Приватные (private) и общие (public) кеши</h4>
<p>Директива "public" указывает, что ответ можно сохранять в любом кеше. Это бывает полезно, если возникает потребность сохранить страницы с HTTP-аутентификацией, или такими кодами ответа, которые обычно не кешируются. Директива же "private" указывает, что ответ предназначен отдельному пользователю и не должен храниться в кеше совместного использования. В этом случае ответ может сохраняться приватным кешем браузера.</p>
<pre class="notranslate">Cache-Control: private
Cache-Control: public
</pre>
<h4 id="Срок_действия_Expiration">Срок действия (Expiration)</h4>
<p>Самой важной здесь является директива "max-age=<seconds>" — максимальное время, в течение которого ресурс считается "свежим". В отличие от директивы {{HTTPHeader("Expires")}}, она привязана к моменту запроса. К неизменяющимся файлам приложения обычно можно применять "агрессивное" кеширование. Примером таких статических файлов могут быть изображения, файлы стилей (CSS) или скриптов (JavaScript).</p>
<p>Подробнее об этом рассказывается в разделе <a href="#Freshness">Свежесть ресурса</a>.</p>
<pre class="notranslate">Cache-Control: max-age=31536000</pre>
<h4 id="Проверка_актуальности">Проверка актуальности</h4>
<p>При использовании директивы "must-revalidate" кеш обязан проверять статус ресурсов с истёкшим сроком действия. Те копии, что утратили актуальность, использоваться не должны. Подробнее об этом рассказано ниже, в разделе <a href="#Cache_validation">Валидация кеша</a>.</p>
<pre class="notranslate">Cache-Control: must-revalidate</pre>
<h3 id="Заголовок_Pragma">Заголовок <code>Pragma </code></h3>
<p>{{HTTPHeader("Pragma")}} является заголовком HTTP/1.0. Он не описан для HTTP-ответов и, таким образом, не может служить надёжной заменой общему заголовку Cache-Control протокола HTTP/1.1, хотя его поведение аналогично "Cache-Control: no-cache" когда поле заголовка Cache-Control опущено в запросе. Использовать его следует только для совместимости с клиентами HTTP/1.0.</p>
<h2 id="Свежесть_сохранённой_копии"><a id="Freshness" name="Freshness">Свежесть сохранённой копии</a></h2>
<p>Однажды попав в кеш, ресурс, теоретически, может храниться там вечно. Однако, поскольку объем хранилища конечен, записи периодически приходится оттуда удалять. Этот процесс называют <em>вытеснением данных из кеша</em> (cache eviction). Кроме того, ресурсы могут изменяться на сервере, поэтому кеш требуется обновлять. Поскольку HTTP является клиент-серверным протоколом, сервера не могут сами обращаться к кешам и клиентам при изменении ресурса; им необходимо договориться о сроке действия сохранённой копии. До его истечения ресурс считается <em>свежим </em>(fresh), после — <em>устаревшим </em>(stale). Алгоритмы вытеснения отдают предпочтение "свежим" ресурсам. Тем не менее, копия ресурса не удаляется из кеша сразу же по истечении её срока действия; при получении запроса на устаревший ресурс кеш передаёт его дальше с заголовком {{HTTPHeader("If-None-Match")}} на случай, если копия все ещё актуальна. Если это так, сервер возвращает заголовок {{HTTPStatus("304")}} <code>Not Modified</code> («не изменялось»), а тело ресурса не посылает, экономя тем самым трафик.</p>
<p>Вот пример того, как протекает этот процесс при использовании совместного кеша прокси:</p>
<p><img alt="Show how a proxy cache acts when a doc is not cache, in the cache and fresh, in the cache and stale." src="https://mdn.mozillademos.org/files/13771/HTTPStaleness.png" style="height: 910px; width: 822px;"></p>
<p>Срок действия (freshnessLifetime) вычисляется на основании нескольких заголовков. Если задан заголовок "Cache-control: max-age=N", то срок действия равен N. Если его нет, а это бывает очень часто, проверяется заголовок {{HTTPHeader("Expires")}}, и, если он есть, то срок действия берётся равным значению заголовка Expires минус значение заголовка Date. Наконец, если нет ни того ни другого, смотрят заголовок Last-Modified. Если он есть, то срок действия равен значению заголовка Date минус значение заголовка Last-modified разделить на 10.<br>
Время устаревания (expirationTime) вычисляется следующим образом:</p>
<pre class="notranslate">expirationTime = responseTime + freshnessLifetime - currentAge
</pre>
<p>где responseTime — это время получения ответа по часам браузера, а currentAge — текущий возраст кеша.</p>
<h3 id="Обновление_статических_ресурсов_Revved_resources">Обновление статических ресурсов (Revved resources)</h3>
<p>Чем больше ресурсов может быть взято из кеша, тем быстрее сайт реагирует на запросы и тем выше его производительность. Из этих соображений их "срок годности" имеет смысл делать как можно большим. Однако, возникает проблема с ресурсами, которые обновляются редко и нерегулярно. Как раз их кеширование даёт больше всего выгоды, но сильно затрудняет обновление. Такие ресурсы можно найти на любой веб-странице: файлы скриптов (JavaScript) и стилей (CSS) изменяются редко, но уж если это произошло, обновление надо произвести как можно быстрее.</p>
<p>Веб-разработчики разработали метод, который Стив Сандерс (Steve Sounders) назвал <em>revving</em><sup><a href="https://www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/">[1]</a></sup>, что можно перевести как "оборачиваемость". Для редко обновляемых файлов используют особый способ именования: в их URL, обычно в имя файла, добавляют номер релиза или версии. Таким образом, каждая новая версия считается отдельным ресурсом, срок устаревания которого отодвинут далеко в будущее, как правило, на год, или больше. Недостатком этого метода является то, что для получения новых версий ресурса приходится обновлять все ссылки на него — это некоторое усложнение, справиться с которым разработчику помогает цепочка инструментов. Обновление статических ресурсов влечёт за собой обновление и часто изменяемых ресурсов. Когда считываются первые, считываются и новые версии вторых.</p>
<p>Этот метод имеет дополнительное достоинство: одновременное обновление двух кешированных ресурсов не приводит к ситуации, при которой устаревшая версия одного ресурса используется вместе с новой версией другого. Это очень важно для сайтов с взаимосвязанными файлами стилей CSS или JS-скриптов — связь может возникнуть, например, из-за ссылок на одни и те же элементы HTML-страницы.</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/13779/HTTPRevved.png"></p>
<p>Номер версии, добавляемый к статическому ресурсу, не обязательно записывать в виде стандартного номера версии наподобие 1.1.3, или другого возрастающего числового значения. Это может быть что угодно, позволяющее избежать совпадений — например, дата.</p>
<h2 id="Валидация_кеша"><a id="Cache_validation" name="Cache_validation">Валидация кеша</a></h2>
<p>Валидация кеша запускается при нажатии пользователем кнопки перезагрузки. Кроме того, она может выполняться в ходе обычного просмотра страниц, если кешированный ответ включает заголовок "Cache-control: must-revalidate". Другим фактором являются настройки кеширования браузера — можно потребовать принудительной валидации при каждой загрузке документа.</p>
<p>При истечении срока годности документа он либо проходит валидацию, либо повторно доставляется с сервера. Валидация может выполняться только если на сервере реализован <em>сильный валидатор </em>или <em>слабый валидатор</em>.</p>
<h3 id="Заголовки_ETag">Заголовки ETag</h3>
<p>Заголовок ответа {{HTTPHeader("ETag")}} является непрозрачным для клиентского приложения (агента) значением, которое можно использовать в качестве сильного валидатора. Суть в том, что клиент, например, браузер, не знает, что представляет эта строка и не может предсказать, каким будет её значение. Если в ответе присутствует заголовок <code>ETag</code>, клиент может транслировать его значение через заголовок {{HTTPHeader("If-None-Match")}} будущих запросов для валидации кешированного ресурса.</p>
<p>Заголовок ответа {{HTTPHeader("Last-Modified")}} можно использовать в качестве слабого валидатора. Слабым он считается из-за того, что имеет 1-секундное разрешение. Если в ответе присутствует заголовок <code>Last-Modified</code>, то для валидации кешированного документа клиент может выводить в запросах заголовок {{HTTPHeader("If-Modified-Since")}}.</p>
<p>При запросе на валидацию сервер может либо проигнорировать валидацию и послать стандартный ответ {{HTTPStatus(200)}} <code>OK</code>, либо вернуть ответ {{HTTPStatus(304)}} <code>Not Modified</code> (с пустым телом), тем самым указывая браузеру взять копию из кеша. В последнем случае в ответ могут входить также заголовки для обновления срока действия кешированного ресурса.</p>
<h2 id="Изменяющиеся_ответы"><a id="Varying_responses" name="Varying_responses">Изменяющиеся ответы</a></h2>
<p>Заголовок HTTP-ответа {{HTTPHeader("Vary")}} определяет, как по заголовкам будущих запросов понять, может ли быть использована копия из кеша, или нужно запросить новые данные у сервера.</p>
<p>Если кеш получает запрос, который можно удовлетворить сохранённым в кеше ответом с заголовком <code>Vary</code>, то использовать этот ответ можно только при совпадении всех указанных в <code>Vary</code> полей заголовка исходного (сохранённого в кеше) запроса и нового запроса.</p>
<p><img alt="The Vary header leads cache to use more HTTP headers as key for the cache." src="https://mdn.mozillademos.org/files/13769/HTTPVary.png" style="height: 817px; width: 752px;"></p>
<p>Это может быть полезно, например, при динамическом предоставлении контента. При использовании заголовка <code>Vary: User-Agent</code> кеширующие сервера, принимая решение об использовании страницы из кеша, должны учитывать агент пользователя. Так можно избежать ситуации, когда пользователи мобильных устройств по ошибке получат десктопную версию вашего сайта. Вдобавок, это может помочь Google и другим поисковым системам обнаружить мобильную версию страницы, и может также указать им на то, что здесь нет никакой подмены контента с целью поисковой оптимизации (<a href="https://en.wikipedia.org/wiki/Cloaking">Cloaking</a>).</p>
<pre class="notranslate">Vary: User-Agent</pre>
<p>Поскольку значение заголовка {{HTTPHeader("User-Agent")}} различается ("varies") у мобильных и десктопных клиентов, закешированный мобильный контент не будет по ошибке отсылаться пользователям десктопов и наоборот.</p>
<h2 id="Смотрите_также">Смотрите также</h2>
<ul>
<li><a href="https://tools.ietf.org/html/rfc7234">RFC 7234: Hypertext Transfer Protocol (HTTP/1.1): Caching</a></li>
<li><a href="https://www.mnot.net/cache_docs">Caching Tutorial – Mark Nottingham</a></li>
<li><a href="https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching">HTTP caching – Ilya Grigorik</a></li>
<li><a href="https://redbot.org/">RedBot</a>, инструмент для проверки относящихся к кешу заголовков HTTP .</li>
</ul>
<p><br>
</p>
|