предисловие
Обобщить:Кэширование всегда было проблемой для фронтенда. Многие фронтэнды не знают, что такое кэширование, что создает себе некоторые проблемы. Как всегда, в этой статье используются простые для понимания слова и примеры для описания кэширования, надеясь получить вам что-нибудь.
-
Оригинальный адрес блога:Подробный кеш
-
Знайте о теме колонки и короткой книги:Фронтальный атакующий (знающий)
-
Адрес блога блогера:Личный блог Дамонаре
Небесно-голубое ждет туманного дождя, а я жду тебя.
текст
Кэширование — это метод сохранения копии ресурса и использования этой копии непосредственно при следующем запросе.
Честно говоря, сначала я действительно не знал, как внедрить кэширование, поэтому выше процитировал относительно официальное определение. Я думаю, что почти каждый разработчик сталкивался с проблемой кэширования, и даже есть много случаев, когда мы бы сказали,这个问题已经修复了,你清理下缓存就好了
. В этой статье мы подробно разберем анекдоты о кэшировании.
🦋Типы кеша
Многие разработчики привыкли называть данные, хранящиеся в файлах cookie, webStorage и IndexedDB, также называемыми кэшами, поскольку все они хранятся на стороне клиента, и между ними нет никакой разницы. На самом деле это не строго.Существование файлов cookie больше позволяет серверу различать пользователей, в то время как webStorage и IndexedDB больше используются для сохранения конкретных данных и хранения больших объемов структурированных данных (файлов/BLOB-объектов) на клиенте.
На самом деле существует только один так называемый кеш - этоЗапросить копию ресурса. Только представьте, что было бы, если бы у нашего клиента была копия каждого ресурса? Клиенты взорвутся, а разработчики сойдут с ума! Поэтому нам нужен протокол для работы с кэшированием, который позволит разработчикам контролировать создание и удаление кэшей. ВОЗ? Кто еще могHTTP
повторять Протокол HTTP определяет множество полей запроса и ответа для кэширования, на этом мы сосредоточимся дальше и изучим, какие поля влияют на кэширование.
Нани? Почему вы просите меня кэшировать? 😱
Это слишком легко сказать 🤣, у кэширования много преимуществ:
- Разгрузить сервер (не нужно каждый раз запрашивать ресурсы);
- Улучшить производительность (открыть локальный ресурс, конечно, гораздо быстрее, чем запросить его обратно и открыть снова);
- Уменьшите потребление трафика (я уверен, вы понимаете);
🤦♀️Тогда проблема возникает снова, раз кеш такой хороший, а вдруг посреди запрашиваемого сервера стоит прокси и он тоже кешируется? Что делать, если прокси-сервер кэширует мои ресурсы, и я не могу получить последние ресурсы с исходного сервера? Конечно, HTTP также подумал об этом призыве. Далее мы будем анализировать его слой за слоем.
🍉 Кэш можно разделить на две категории на макроуровне:приватный кеша такжеобщий кеш. Общие кэши — это те кэши, которые могут кэшироваться прокси на всех уровнях. Частный кеш — это кеш, который является эксклюзивным для пользователей и не может быть закэширован прокси на всех уровнях.
🐜 Микроскопически его можно разделить на следующие три категории:
1. Кэш браузера
Я считаю, что если вы часто пользуетесь определенным браузером 🌎 (Chrome, Firefox, IE и т. д.), вы должны знать, что в этих браузерах есть функция очистки кеша в настройках, функция этой функции заключается в удалении сохраненных ресурсов. на свой локальный диск.Скопируйте, то есть очистите кеш.
Смысл кеша в том, чтобы иметь возможность быстрее реагировать, когда пользователь нажимает кнопку «Назад» или снова посещает страницу. Особенно на веб-сайтах с многостраничными приложениями, если вы используете одно и то же изображение на нескольких страницах, кэширование этого изображения становится особенно полезным. 😏
2. Кэш прокси-сервера
Принцип кеширования прокси-сервера аналогичен кешированию браузера, но масштаб намного больше, потому что он обеспечивает механизм кеширования для тысяч пользователей, а крупные компании и крупные интернет-провайдеры обычно настраивают их на брандмауэре или как независимые оборудование для эксплуатации. (Если ниже не указано иное, все ссылки на кэш-серверы относятся к прокси-серверам.)
Поскольку кеш-серверы не являются частью клиентского или исходного сервера, они существуют в сети, и маршрутизация запросов должна проходить через них, чтобы они вступили в силу, поэтому вы можете фактически установить прокси-сервер браузера вручную или перенаправить его через промежуточный сервер, чтобы пользователь, естественно, не будет знать о существовании прокси-сервера. 🤥
Кэш прокси-сервера — это общий кеш не только для одного пользователя, но и часто используемый большим количеством пользователей, поэтому он очень эффективен для сокращения времени отклика и использования полосы пропускания: поскольку один и тот же кеш может использоваться повторно несколько раз.
3. Кэш шлюза
также называетсяКэш прокси или обратный кеш прокси, шлюз также является промежуточным сервером, а кеш шлюза обычно развертывается администратором веб-сайта, чтобы повысить производительность веб-сайта. 🙂
CDNS (Network Content Distributor) распределяет кэш шлюза по всему Интернету (или его части) и продает услугу кеша веб-сайтам, которые в нем нуждаются. Например, такие услуги есть у отечественных Qiniuyun и Youpaiyun.
4. Кэш базы данных
Кэширование базы данных означает, что когда наше приложение очень сложное и таблицы естественно сложные, мы должны выполнять частые запросы к базе данных, что может привести к перегрузке базы данных.Хороший способ — поместить запрошенные данные в память, и в следующий раз запрос просто извлекается непосредственно из памяти. В этой статье не рассматривается кэширование базы данных. 🙃
🦄 Политика кеширования браузера
Кэшированная цель:
- Успешный ответ на поисковый запрос: для запроса GET код состояния ответа: 200, что означает успех. ответ, содержащий, например, HTML-документ, изображение или файл;
- Инвариантное перенаправление: код состояния ответа: 301;
- Доступные кешированные ответы: Код статуса ответа: 304, это вызывает сомнения, Chrome будет кэшировать настройки кеша в 304, Firefox;
- Ошибка ответа: Страница с кодом ответа: 404;
- Неполный ответ: код состояния ответа 206, возвращается только частичная информация;
- За исключением запросов GET, если ответ соответствует определенному ключу кэша;
Вышеизложенное дает представление о том, что мы можем и должны кэшировать. 🤗
Обработка кеша браузером определяется заголовками ответов, возвращаемыми при первом запросе ресурса.
Так как же браузер определяет, следует ли кэшировать ресурс и как его кэшировать? Заголовки ответа! Заголовки ответа! Важные вещи говорятся трижды. ✌️
Мы видим:
Age:23146
Cache-Control:max-age=2592000
Date:Tue, 28 Nov 2017 12:26:41 GMT
ETag:W/"5a1cf09a-63c6"
Expires:Thu, 28 Dec 2017 05:27:45 GMT
Last-Modified:Tue, 28 Nov 2017 05:14:02 GMT
Vary:Accept-Encoding
1. Фаза сильного кеша
Приведенные выше заголовки запросов взяты из заголовков ответа файла CSS на главной странице Baidu. Я удалил некоторые поля, не связанные с кешированием, и оставил только указанную выше часть. Давайте проанализируем,Expires
Это определяющее кеш поле в HTTP/1.0, которое указывает абсолютное время истечения срока действия кеша.Cache-Control:max-age=2592000
Это поле, связанное с кешем, определено в HTTP/1.1 и указывает относительное время истечения срока действия кеша. Разумеется, в приоритете старшая версия.max-age > Expires
.
ЭтоФаза сильного кеша, когда браузер снова попытается получить доступ к файлу CSS и обнаружит, что есть кеш этого файла, он будет судить о том, истек ли срок его действия по последнему ответу.Если срок действия еще не истек, используйте кеш. Загрузка файла, КОНЕЦ! ✌️
Браузер Firefox отображается как серый код состояния 200.
Код состояния браузера Chrome выглядит следующим образом:
200 (из кеша диска) или 200 ОК (из кеша памяти)
**Подробнее:** Что касается получения кеша с диска или из памяти, я просмотрел много информации и пришел к более правдоподобному выводу: Chrome решит, где хранить кеш, на основе использования локальной памяти, если скорость использования памяти высока, она будет помещена на диск, а скорость использования памяти будет временно помещена в память. Это может разумно объяснить, почему один и тот же ресурс иногда находится в кеше памяти, а иногда в кеше диска.
Итак, что произойдет, когда срок действия этого файла CSS истечет?ETag
а такжеLast-Modified
Пришло время сиять.
во-первыхLast-Modified
, в этом поле указано время последнего изменения файла;
ETag
Шерстяная ткань? ETag это тэг для файла.Ну можно сказать что конкретный метод генерации HTTP не дает четкого метода,поэтому по идее не имеет значения, лишь бы метод генерации не повторялся.Например,использование хэш-функция предотвращения коллизий для содержимого ресурса, использующая хэш последней измененной временной метки или даже просто номер версии.
####2. Этап согласования кэша
Используя эти два поля, браузер может ввестиЭтап согласования кэша, когда браузер снова попытается получить доступ к файлу CSS и обнаружит, что срок действия кеша истек, он будет перенесен в заголовок этого запроса.If-Moified-Since
а такжеIf-None-Match
Эти два поля, сервер использует эти два поля, чтобы определить, был ли изменен ресурс, и возвращает код состояния, если есть модификация.200 и новый контент, если не изменен, верните код состояния304, браузер получает код состояния 200, и он должен быть обработан должным образом (эквивалентно доступу к этому файлу в первый раз), и обнаруживается, что он возвращает304, поэтому я знаю, что локальный кеш все еще доступен, хотя срок его действия истек, поэтому я загружаю локальный кеш. Затем установите кеш на основе новых возвращенных заголовков ответа. (Этот шаг отличается. Обнаружено, что обработка в разных браузерах отличается. Хром установит кеш на 304, а фаерфокс нет) 😑
Содержимое этих двух полей выглядит следующим образом (соответственно и указанное вышеLast-Modified
,ETag
Перенесенное значение соответствует):
If-Moified-Since: Tue, 28 Nov 2017 05:14:02 GMT
If-None-Match: W/"5a1cf09a-63c6"
На этом кэш согласования закончился.
3. Этап эвристического кэширования
Давайте изменим заголовок ответа выше:
Age:23146
Cache-Control: public
Date:Tue, 28 Nov 2017 12:26:41 GMT
Last-Modified:Tue, 28 Nov 2017 05:14:02 GMT
Vary:Accept-Encoding
Ты нашел это? Ни одно из полей, которые браузеры используют для определения срока действия кеша! так что мне теперь делать? Некоторые люди могут сказать, что следующий запрос напрямую попадает в стадию кэша согласования, несяIf-Moified-Since
О, нет, в браузере тоже естьЭтап эвристического кэширования😎
В соответствии с разницей во времени между двумя полями времени Date и Last-Modified в заголовке ответа 10% значения берется в качестве периода времени кэширования.
Это фаза эвристического кэширования. Эту стадию легко игнорировать, но на самом деле она всегда играет свою роль. Так что в дальнейшем процессе разработки, если вы столкнетесь с такими默认缓存
Яма, не кричи, не сердись, браузер просто следует протоколу эвристического кэширования.
Я нарисовал следующую картинку, чтобы объяснить процесс всей стратегии кэширования браузера:
👌Для ознакомления со стратегией кэширования давайте подробно проанализируем содержимое различных полей заголовка HTTP и взаимосвязь между ними.
🦀 Поля заголовков, связанные с кэшированием в HTTP
Что такое HTTP-сообщение? Это HTTP-сообщение, которое является концепцией, в основном состоит из следующих двух частей:
- заголовок: содержит множество полей, таких как: cookie, кеш, размер сообщения, формат сообщения и т. д.);
- тело: Фактическая часть передаваемого HTTP-запроса, например: документ HTML, файл js;
Выше мы знаем процесс обработки браузером кеша, а также кратко упомянули несколько связанных полей. 🤧 Далее давайте подробно рассмотрим эти поля:
1. Обычные поля заголовка
Имя поля | иллюстрировать |
---|---|
Cache-Control | Контролирует конкретное поведение кэша |
Pragma | Устаревшее поле из HTTP 1.0, когда значение «без кеша» для принудительного кеша проверки |
Date | Дата и время создания сообщения (это поле используется на этапе эвристического кэширования) |
2. Поля заголовка ответа
Имя поля | иллюстрировать |
---|---|
ETag | Уникальный идентификатор сгенерированного сервером ресурса |
Vary | Информация управления, кэшированная прокси-сервером |
Age | Как долго ресурс хранится в кеширующем прокси (зависит от размера max-age и s-maxage) |
3. Поля заголовка запроса
Имя поля | иллюстрировать |
---|---|
If-Match | Условный запрос, несущий ETag ресурса в предыдущем запросе, сервер судит, есть ли в файле новая модификация по этому полю |
If-None-Match | В отличие от If-Match, сервер оценивает, есть ли в файле новые модификации на основе этого поля. |
If-Modified-Since | Сравните, согласовано ли время последней модификации двух доступов до и после ресурса. |
If-Unmodified-Since | Сравните, согласовано ли время последней модификации двух доступов до и после ресурса. |
4. Поля заголовка сущности
Имя поля | иллюстрировать |
---|---|
Expires | Скажите клиенту абсолютное время для аннулирования кэша ресурса |
Last-Modified | Ресурсы времени последнего изменения |
🦅 Управление кешем браузера
HTTP/1.1Всего стандартизировано 47 полей заголовков, а целых 12 связаны с кэшированием. Следующие два раздела познакомят вас один за другим. 🤓
1. Cache-Control
Директива cache-control сообщает клиенту или серверу, как обращаться с кешем. Это также тот, у которого больше всего инструкций в 11 полях, давайте сначала посмотримзапрос инструкции:
инструкция | параметр | иллюстрировать |
---|---|---|
no-cache | без | Заставить исходный сервер снова пройти аутентификацию |
no-store | без | Не кэшировать содержимое запроса или ответа |
максимальный возраст = [секунды] | Длительность кеша, в секундах | Продолжительность кеша также является максимальным значением возраста ответа. |
мин-свежий=[секунды] | требуется | Ожидайте, что ответ все еще будет действительным в течение указанного времени |
no-transform | без | Прокси не может изменить тип носителя |
only-if-cached | без | получить из кеша |
cache-extension | - | Токен новой инструкции (токен) |
Отвечать на инструкции:
инструкция | параметр | иллюстрировать |
---|---|---|
public | без | Любая сторона может кэшировать ресурс (клиент, прокси и т. |
private | можно опустить | Только определенные пользователи могут кэшировать ресурс |
no-cache | можно опустить | Валидность должна быть подтверждена перед кэшированием |
no-store | без | Не кэширует содержимое запроса или ответа |
no-transform | без | Прокси не может изменить тип носителя |
must-revalidate | без | Можно кэшировать, но необходимо перепроверить на исходном сервере |
proxy-revalidate | без | Промежуточный кеш-сервер требуется для повторного подтверждения достоверности кэшированного ответа. |
максимальный возраст = [секунды] | Длительность кеша, в секундах | Продолжительность кеша также является максимальным значением возраста ответа. |
s-maxage=[секунды] | требуется | Максимальное значение возраста для ответов сервера общедоступного кэша |
cache-extension | - | новый токен инструкции |
Обратите внимание, что многие люди ошибочно принимают директиву no-cache за отсутствие кэширования. Это неточно. No-cache означает, что его можно кэшировать, но каждый раз, когда вы его используете, вы должны запрашивать сервер, чтобы проверить, доступен ли кэш. no-store — не кэшировать содержимое. Другие команды также могут использоваться в комбинации, например:
Cache-Control: max-age=100, must-revalidate, public
Приведенная выше инструкция означает, что кеш действителен в течение 100 секунд, после чего доступ должен отправить запрос на исходный сервер для проверки.Этот кеш может кэшироваться прокси-серверами и клиентами.
2. Pragma
Это поле в HTTP/1.0, новысокий приоритет, тест показал, что приоритет Pragma в Chrome и Firefox выше, чем у Cache-Control и Expires.Для обратной совместимости это поле по-прежнему играет свою роль. 🤔 Как правило, мы можем использовать это так:
<meta http-equiv="Pragma" content="no-cache">
Pragma — это общее поле заголовка, при использовании которого на стороне клиента нам обычно требуется добавить вышеуказанный метатег в html (и, возможно, также придетсяСделайте несколько хаков и поместите их за тело.
На самом деле эта форма отключения кеша имеет ограниченное применение:
- Только IE может распознать значение этого метатега, другие основные браузеры могут распознать только
Cache-Control: no-store
метатеги (см.происхождение) - Распознавание значения этого метатега в IE не обязательно добавляет Pragma в поле запроса, но заставляет текущую страницу каждый раз отправлять новый запрос (только страница, ресурсы на странице не затрагиваются). ——Говоря о механизме кеширования браузера http
Читатели могут позже скопировать код, имитирующий принятие решений на стороне сервера, для тестирования.
Добавлен ответ сервера'Pragma': 'no-cache'
, браузер ведет себя как принудительное обновление.
3. Expires
Это еще одно поле HTTP/1.0, и вышеупомянутое определение является абсолютным временем истечения срока действия кеша.
Точно так же мы также можем использовать его непосредственно в html-файле:
<meta http-equiv="expires" content="Thu, 30 Nov 2017 11:17:26 GMT">
Что делать, если установлено, что время истекло? ДА! ! ! Обновление страницы приведет к повторной отправке запроса.
**Pragma отключает кэширование.Если вы определяете время, которое еще не истекло для Expires, поле Pragma будет иметь более высокий приоритет. **🤖
🤖Expires имеет большой недостаток, то есть он возвращает время сервера, но для суждения используется время клиента, что делает Expires очень пассивным, потому что пользователь может изменить время клиента, в результате чего суждения ошибки времени кеша, это также введениеCache-Control:max-age
Одна из причин директивы.
4. Last-Midified
Следующие несколько полей являются проверочными полями или полями, которые играют роль на этапе согласования и кэширования. Первое — Last-modified, Это поле не только играет роль в согласовании кеша, но также играет решающую роль на этапе эвристического кеша.
Когда браузер запрашивает URL-адрес в первый раз, код состояния возврата на стороне сервера будет 200, содержимым ответа является ресурс, запрошенный клиентом, и имеетсяLast-Modified
Атрибут отмечает, когда этот файл последний раз модифицировался на стороне сервера. так:
Last-Modified : Fri , 12 May 2006 18:53:33 GMT
If-Modified-Since
Когда браузер запрашивает этот URL во второй раз, в соответствии с протоколом HTTP, браузерLast-Modified
Значение хранится вIf-Modified-Since
Он отправляется на сервер для проверки того, был ли изменен ресурс. так:
If-Modified-Since : Fri , 12 May 2006 18:53:33 GMT
сервер черезIf-Modified-Since
поле, чтобы определить, был ли ресурс изменен во время этих двух посещений, чтобы решить, следует ли возвращать полный ресурс. Если ресурс изменяется нормально, код состояния равен 200. Если изменений нет, возвращается только заголовок ответа, а код состояния — 304, который информирует браузер о том, что локальный кеш ресурса все еще доступен.
использовать:
- Убедитесь, что локальный кеш доступен
If-Unmodified-Since
Это поле буквально иIf-Modified-Since
Вместо этого, но не наоборот. Возвращает 200 и ресурс, если файл не был изменен между обращениями, и возвращает код состояния 412 (ошибка предварительной обработки), если файл был изменен.
использовать:
- с содержанием
If-Range
Запрос диапазона заголовка сообщения используется в сочетании для реализации функции возобновления загрузки с точки останова, то есть, если ресурс не изменен, загрузка будет продолжена, а если ресурс изменен, смысл возобновления загрузки загрузка будет потеряна. - В запросах POST и PUT оптимизирован контроль параллелизма, то есть при редактировании документа несколькими пользователями, если ресурсы сервера были изменены, редактирование будет отклонено для отправки.
😈Last-Modified
Недостатков несколько: невозможно точно судить о том, действительно ли изменен ресурс, например, некий файл часто меняется много раз в течение 1 секунды, и о нем нельзя судить по времени Last-Modified (единица измерения секунды). Например, ресурс только изменен, но фактическое содержимое не изменилось, и Last-Modified не может судить об этом, поэтому он также был введен в HTTP/1.1.ETag
это поле👇
5. ETag
Сервер может сгенерировать уникальный идентификатор (например, идентификатор md5) для ресурса с помощью некоторого самоопределяемого алгоритма, а затем поместить этот идентификатор в заголовок ответа и передать его клиенту, когда браузер запрашивает определенный URL-адрес для первого время. Статус возврата на стороне сервера будет 200.
ETag: abc-123456
Значение ETag может содержать префикс W/, указывающий на необходимость использования слабого алгоритма сравнения (это лишнее, так как If-None-Match использует и только использует этот алгоритм). 🙄
If-None-Match
If-None-Match и If-Modified-Since существуют одновременно, If-None-Match имеет более высокий приоритет.
Когда браузер запрашивает этот URL во второй раз, в соответствии с протоколом HTTP, браузер сохраняет значение первого ETag в If-None-Match и отправляет его на сервер, чтобы проверить, был ли изменен ресурс. так:
If-None-Match: abc-123456
В запросе Get сервер вернет запрошенный ресурс тогда и только тогда, когда значение атрибута ETag любого ресурса на сервере соответствует указанному в этом заголовке, а код ответа200. Если значение ETag ни для одного ресурса не совпадает, верните304код состояния.
POST, PUT и другие запросы на изменение файла, если нет соответствующего значения ETag ресурса, возвращается код состояния 412.
If-Match
В случае, когда метод запроса — GET) и HEAD, сервер будет запрашивать только те ресурсы, которые удовлетворяют требованиям, перечисленным в этом заголовке.ETag
Один из ресурсов будет возвращен. Для PUT или других небезопасных методов ресурсы могут быть загружены только при соблюдении условий.
использовать:
- Методы For GET и HEAD, используемые с заголовком Range, могут быть использованы для обеспечения того, чтобы областью действия нового запроса был тот же ресурс, что и областью действия предыдущего запроса. Если ETag не может быть сопоставлен, он должен вернуться416(Запрос диапазона не может быть удовлетворен) ответ.
- Для других методов, особенно PUT,
If-Match
Заголовок можно использовать, чтобы избежать потери обновлений. Его можно использовать для определения того, что то, что пользователь хочет загрузить, не перезапишет обновления, сделанные после извлечения исходного ресурса. Если запрошенные условия не соблюдены, то нужно вернуть412(Ошибка предварительной обработки) Ответ.
конечно иLast-Modified
Напротив, у ETag есть и свои недостатки, например, из-за необходимости генерировать идентификаторы для ресурсов производительностью приходится жертвовать. 😕
О сильной контрольной сумме и слабой контрольной сумме:
ETag 1 | ETag 2 | Strong Comparison | Weak Comparison |
---|---|---|---|
W/"1" | W/"1" | no match | match |
W/"1" | W/"2" | no match | no match |
W/"1" | "1" | no match | match |
"1" | "1" | match | match |
🐝Управление кешем сервера
когдаExpires
а такжеCache-Control:max-age=xxx
Наличие обоих зависит от HTTP-версии приложения кэш-сервера. Сервер, использующий HTTP/1.1, будет отдавать приоритет max-age и игнорировать Expires, в то время как сервер кэширования, использующий HTTP/1.0, будет отдавать приоритет Expires и игнорировать max-age. Далее посмотрите на два поля, относящиеся к кэш-серверу.
6. Vary
Для чего используется Вари? Представьте себе такой сценарий: на определенной веб-странице контент, предоставляемый веб-сайтом мобильному терминалу, отличается, как кэш-сервер может отличить мобильный терминал от терминала ПК? Я не знаю, заметили ли вы, что браузер будет содержать поле UA для указания источника в каждом запросе, поэтому мы можем использоватьUser-Agent
поле для различения разных клиентов, используется следующим образом:
Vary: User-Agent
Другой пример: если исходный сервер включает сжатие gzip, но пользователь использует более старый браузер, который не поддерживает сжатие, как возвращается кеш-сервер? Его можно установить так:
Vary: Accept-Encoding
Конечно, вы также можете использовать:
Vary: User-Agent, Accept-Encoding
Это означает, что кэш-сервер будетUser-Agent
а такжеAccept-Encoding
Два поля заголовка запроса для различения кешированных версий. По этим двум полям в заголовке запроса решите, что возвращать клиенту.
7. Age
Это поле говорит о том, как долго ресурс существует в кэш-сервере, о чем также упоминалось ранее.Cache-Control: max-age=[秒]
максимальное значение возраста.
В чем смысл существования этого поля? Используется, чтобы отличить запрошенный ресурс от исходного сервера или кеша сервера кеша.
🤧 Но это должно оцениваться в сочетании с другим полем, а именно Дата, то есть время, когда сообщение было создано.
Date
Если вы нажмете F5 для частого обновления и обнаружите, что дата в ответе не изменилась, это означает, что кеш сервера кеша поражен, и один из следующих ответов — 🍐:
Accept-Ranges: bytes
Age: 1016859
Cache-Control: max-age=2592000
Content-Length: 14119
Content-Type: image/png
Date: Fri, 01 Dec 2017 12:27:25 GMT
ETag: "5912bfd0-3727"
Expires: Tue, 19 Dec 2017 17:59:46 GMT
Last-Modified: Wed, 10 May 2017 07:22:56 GMT
Ohc-Response-Time: 1 0 0 0 0 0
Server: bfe/1.0.8.13-sslpool-patch
Изображение выше взято из поля ответа изображения на главной странице Baidu. Мы можем видеть Age=1016859, что указывает на то, что этот ресурс существует в кэш-сервере в течение 1016859 секунд. Если файл будет изменен или заменен, возраст снова начнет накапливаться с 0.
Значение заголовка Age обычно близко к 0. Указывает, что данный объект сообщения только что получен с исходного сервера, другие значения представляют собой разницу между текущим системным временем прокси-сервера и значением общего заголовка сообщения Date в этом ответном сообщении.
Приведенный выше вывод сводится к уравнению:
静态资源Age + 静态资源Date = 原服务端Date
🐲 Влияние поведения пользователя на кеш
После долгих поисков, есть ли какое-либо авторитетное резюме по этому аспекту, и я был удивлен, обнаружив его в энциклопедии Baidu, я добавил ответ на операцию принудительного обновления браузера пользователем. Принудительное обновление, под окном естьCtrl+F5
, под маком естьcommand+shift+R
Готово. :с облегчением:
действовать | иллюстрировать |
---|---|
открыть новое окно | Если указанное значение управления кешем является закрытым, без кеша, с обязательной повторной проверкой, то сервер будет повторно посещен при открытии нового окна. А если указано значение max-age, то сервер не будет повторно посещен в течение периода времени этого значения, например: Cache-control: max-age=5 означает, что веб-страница не будет повторно посещена в течение 5 секунд после посещения этого сервер веб-страниц. |
Введите в адресной строке | Если значение является закрытым или требует повторной проверки, доступ к серверу будет осуществляться только при первом доступе к нему, и доступ к нему не будет осуществляться позже. Если значение равно no-cache, к нему будет обращаться каждый раз. Если значение равно max-age, повторных посещений не будет, пока оно не истечет. |
Нажмите кнопку «Назад» | Если значение является частным, обязательным для повторной проверки, максимальным возрастом, оно не будет пересматриваться, а если оно не кэшировано, оно будет пересматриваться каждый раз. |
Нажмите кнопку обновления | Независимо от значения, к нему будут обращаться повторно (возможный код возврата: 200, 304, это обрабатывается по-разному в разных браузерах, FireFox — нормально, Chrome включит кеширование (200 из кеша)) |
Нажмите кнопку принудительного обновления | Повторный запрос как первая запись (код возврата 200) |
:wink: Что делать, если вы хотите запретить браузеру отправлять новый запрос на аутентификацию, когда браузер нажимает кнопку «обновить»? Как его найти, знайте ответ выше и динамически добавляйте ресурсы через скрипты после загрузки страницы:
$(window).load(function() {
var bg='http://img.infinitynewtab.com/wallpaper/100.jpg';
setTimeout(function() {
$('#bgOut').css('background-image', 'url('+bg+')');
},0);
});
🐩 Кэш HTML5
Эту часть подготовки следует назвать автономным хранением. Сейчас чаще используютAppcache
,ноAppcache
был удален из веб-стандартов в обозримом будущем,ServiceWorker
Может более подходящее решение.
1. Appcache
Это новая функция HTML5, которая позволяет пользователям получать доступ к страницам без подключения к сети через автономное хранилище. Документ может быть загружен в обычном режиме, даже если пользователь нажимает кнопку «Обновить» в автономном режиме.
Метод использования следующий, представленный в файле HTML.appcache
документ:
<!DOCTYPE html>
<html manifest="manifest.appcache">
<head>
<meta charset="UTF-8">
<title>***</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
🤠 в веб-приложенияхmanifest
Атрибут можно указать как относительный путь к файлу манифеста кэша или как абсолютный URL-адрес (абсолютный URL-адрес должен иметь то же происхождение, что и приложение). Файл манифеста кэша может использовать любое расширение, но тип MIME, который его передает, должен бытьtext/cache-manifest。
**Примечание.** На сервере Apache, чтобы установить тип MIME для файлов манифеста (.appcache), добавьте
AddType text/cache-manifest .appcache
.
CACHE MANIFEST
# 注释:需要缓存的文件,无论在线与否,均从缓存里读取
# v1 2017-11-30
# This is another comment
/static/logo.png
# 注释:不缓存的文件,始终从网络获取
NETWORK:
example.js
# 注释:获取不到资源时的备选路径,如index.html访问失败,则返回404页面
FALLBACK:
index.html 404.html
Выше приведен пример полного файла манифеста кэша.
**Примечание.** Домашняя страница обязательно будет кэширована, так как AppCache в основном используется для автономных приложений. Если домашняя страница не кэширована, ее нельзя просматривать в автономном режиме, поэтому добавление index.html в NETWORK не даст никакого эффекта.
На самом деле эта функция была удалена из веб-стандарта, но многие браузеры до сих пор поддерживают ее, поэтому я упоминаю ее здесь.
Вы можете протестировать его с последним Firefox (версия 57.0.1), в консоли будет эта строка 👉:
API-интерфейс App Cache (AppCache) устарел и будет удален через несколько дней. Для автономной поддержки попробуйте использовать Service Worker.
В последней версии Chrome (версия 62.0.3202.94) этого предупреждения нет. 🐻
AppCache
Я думаю о следующих причинах, почему он не популярен:
- После использования манифеста нет возможности очистить эти кеши, можно только обновить кеш, или пользователь должен очистить кеш браузера;
- Если один из обновленных ресурсов не обновится, то все ресурсы не обновятся, и будет использоваться предыдущая версия кеша;
- Домашняя страница будет принудительно кэширована (страницы, использующие манифест) и не может быть очищена;
- файлы apache могут не обновляться вовремя, потому что основные браузеры по-разному обрабатывают файлы appcache;
- Как только вышеперечисленные недостатки исправятся, пользователи будут в бешенстве, и разработчики будут в бешенстве!
2. Service Worker
Сервисный работник по-прежнему является экспериментальной функцией и не рекомендуется для онлайн-сред. 🐒 Вот краткое введение.
Service Worker по существу действует как прокси-сервер между веб-приложением и браузером.
🙂Сначала небольшая история:
Мы все знаем, что js-движок браузера обрабатывает js в однопоточном режиме, это как большой босс, и он делает только одну вещь одновременно (просто так высокомерно).Основываясь на этом недостатке,W3C(HR) Нанял секретаря для Биг Босса (web worker
), большой босс может оставить секретарю тривиальные вопросыweb worker
Сделайте это, отправьте WeChat, когда закончите (postMessage
) уведомить большого босса, большой босс проходитonmessage
найти секретаряweb worker
результат того, что сделано. Вечером пора уходить с работы! Большой босс пошел домой, чтобы уговорить сына, а секретарша ушла на свидание, и никто не работал сверхурочно! Как это работает!W3C(HR) предложил еще одного рекрутаПрограмма 🐵идея идеи, хорошо,Service Worker
Успешная заявка! тогда,Программа 🙈Просто придерживаюсь работы и начинаю бесконечную сверхурочную работу. В целом эта обезьяна работает так:
- Фоновая синхронизация данных
- Отвечать на запросы ресурсов из других источников
- Централизованное получение обновлений данных, требующих значительных вычислительных ресурсов, таких как информация о геолокации и гироскопе, чтобы несколько страниц могли использовать один и тот же набор данных.
- Компиляция модулей и управление зависимостями для CoffeeScript, LESS, CJS/AMD и т. д. на стороне клиента (в целях разработки)
- Хук фоновой службы
- Пользовательские шаблоны для определенных шаблонов URL
- Улучшения производительности, такие как предварительная выборка ресурсов, которые могут понадобиться пользователям.
Примечание. Сервисные работники превосходят предыдущие аналогичные попытки (например, AppCache, упомянутые выше), потому что они не могут поддерживать завершение операций в случае сбоя. Сервисные работники имеют более детальный контроль над всем. Как это контролировать?
Сервисные работники используют Promise, важную функцию ES6, и используют новый API fetch при перехвате запросов Причина, по которой используется fetch, заключается в том, что fetch возвращает объект Promise. Можно сказать, что важными компонентами Service Workers являются три части: события, запросы Promise и Fetch. Хорошо, болтовня дешева, покажи код. 🤓
Сначала давайте посмотрим на файл app.js: скажите браузеру зарегистрировать файл JavaScript в качестве сервис-воркера, проверьте, доступен ли API сервис-воркера, и зарегистрируйте сервис-воркера, если он доступен:
//使用 ServiceWorkerContainer.register()方法首次注册service worker。
if (navigator.serviceWorker) {
navigator.serviceWorker.register('./sw.js', {scope: './'})
.then(function (registration) {
console.log(registration);
})
.catch(function (e) {
console.error(e);
});
} else {
console.log('该浏览器不支持Service Worker');
}
Давайте посмотрим на файл sw.js конкретно как на сервисного работника Пример выглядит следующим образом:
const CACHE_VERSION = 'v1'; // 缓存文件的版本
const CACHE_FILES = [ // 需要缓存的文件
'./test.js',
'./app.js',
'https://code.jquery.com/jquery-3.0.0.min.js'
];
self.addEventListener('install', function (event) { // 监听worker的install事件
event.waitUntil( // 延迟install事件直到缓存初始化完成
caches.open(CACHE_VERSION)
.then(function (cache) {
console.log('缓存打开');
return cache.addAll(CACHE_FILES);
})
);
});
self.addEventListener('activate', function(event) {// 监听worker的activate事件
event.waitUntil(// 延迟activate事件直到
caches.keys().then(function(keys) {
return Promise.all(keys.map(function(key, i){
if(key !== CACHE_VERSION){
return caches.delete(keys[i]); // 清除旧版本缓存
}
}))
})
)
});
self.addEventListener('fetch', function(event) { // 截取页面的资源请求
event.respondWith(
caches.match(event.request).then(function(res) { // 判断缓存是否命中
if (res) { // 返回缓存中的资源
return res;
}
_request(event); // 执行请求备份操作
})
)
});
function _request(event) {
var url = event.request.clone();
return fetch(url).then(function(res) {// 使用fetch请求线上资源
// 错误判断
if (!res || res.status !== 200 || res.type !== 'basic') {
return res;
}
var response = res.clone(); // 创建了一个响应对象的克隆,储藏在一个单独的变量中
caches.open(CACHE_VERSION).then(function(cache) {// 缓存从线上获取的资源
cache.put(event.request, response);
});
return res;
})
}
Очистить Service Worker также просто:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js', {scope: './'}).then(function(registration) {
// registration worked
console.log('Registration succeeded.');
registration.unregister().then(function(boolean) {
// if boolean = true, unregister is successful
});
}).catch(function(error) {
// registration failed
console.log('Registration failed with ' + error);
});
};
По сравнению с AppCache, API Service Worker значительно расширился, а использование стало более сложным, но видно, что за Service Worker будущее, и он еще более эффективен для веб-приложений. В дополнение к Chrome и Firefox, браузеры, которые теперь поддерживают Service Workers, недавно добавили новую силу — Safari также поддерживает Service Workers. Ожидайте, что он будет сиять в будущем. 🤗
🦉 Симуляция для принятия решений на стороне сервера
Как показано ниже, используйте собственный код узла, чтобы просто смоделировать процесс отправки ответа с сервера, включая процесс согласования кеша:
var http = require('http');
var fs = require('fs');
var url = require('url');
process.env.TZ = 'Europe/London';
let tag = '123456';
http.createServer( function (request, response) {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
const fileMap = {
'js': 'application/javascript; charset=utf-8',
'html': 'text/html',
'png': 'image/png',
'jpg': 'image/jpeg',
'gif': 'image/gif',
'ico': 'image/*',
'appcache': 'text/cache-manifest'
}
fs.readFile(pathname.substr(1), function (err, data) {
if (request.headers['if-none-match'] === tag) {
response.writeHead(304, {
'Content-Type': fileMap[pathname.substr(1).split('.')[1]],
'Expires': new Date(Date.now() + 30000),
'Cache-Control': 'max-age=10, public',
'ETag': tag,
'Last-Modified': new Date(Date.now() - 30000),
'Vary': 'User-Agent'
});
} else {
response.writeHead(200, {
'Content-Type': fileMap[pathname.substr(1).split('.')[1]],
'Cache-Control': 'max-age=10, public',
'Expires': new Date(Date.now() + 30000),
'ETag': tag,
'Last-Modified': new Date(Date.now() - 30000),
'Vary': 'User-Agent'
});
response.write(fs.readFileSync(pathname.substr(1)));
}
response.end();
});
}).listen(8081);
Код, как указано выше. Если вы раньше не использовали узел, скопируйте код и сохраните его как file.js, установите узел и введите в командной строкеnode file.js
, вы можете создать файл index.html в том же каталоге, ссылаться на некоторые изображения, CSS и другие файлы в файле html, а также на ввод браузера.localhost:8081/index.html
Проведите симуляцию. 🤓
🦆 Несколько вопросов и ответов о кэшировании
1. Проблема: запрос кэшируется, в результате чего новый код не действует.
решение:
- Добавлен ответ сервера
Cache-Control:no-cache,must-revalidate
инструкция; - Изменить заголовки запроса
If-modified-since:0
илиIf-none-match
; - Измените URL-адрес запроса и добавьте случайное число после URL-адреса запроса. Случайным числом может быть отметка времени или хеш-значение, например:damonare.cn?a=1234
2. Проблема: из-за кэша сервера локальный код не обновляется.
решение:
- Разумно установите директиву Cache-Control:s-maxage;
- Установите директиву Cache-Control:private, чтобы прокси-сервер не кэшировал ресурсы;
- Кэш CDN можно обновить с помощью интерфейса обновления кеша, установленного администратором;
3. Вопрос: В чем разница между Cache-Control: max-age=0 и no-cache
отвечать:
max-age=0
а такжеno-cache
Он должен быть разным по тону.max-age=0
это сообщить клиенту, что срок действия кеша ресурса истекаетдолженПроверьте достоверность кеша на сервере. а такжеno-cache
затем скажите клиенту использовать кеш переддолженПроверьте достоверность кеша на сервере.
постскриптум
Справочная документация: