В начале интервью часто задают второй большой вопросhttp缓存
связанная информация. Если честно, есть много деталей, связанных с HTTP-кешингом, и общие версии протокола HTTP являются 1.0 и 1.1 (эта статья не обсуждает http2.0).
заголовки, связанные с кешем
Давайте сначала перечислим заголовки ответа на запрос, связанные с кэшированием.
- Expires
Заголовок ответа, представляющий время истечения срока действия ресурса.
- Cache-Control
Заголовки запроса/ответа, поля управления кешем для точного управления политикой кеша.
- If-Modified-Since
Заголовок запроса, время последней модификации ресурса, сообщается браузером серверу.
- Last-Modified
Заголовок ответа, время последней модификации ресурса, сообщается сервером браузеру.
- Etag
Заголовок ответа, идентификатор ресурса, сообщается сервером браузеру.
- If-None-Match
Заголовок запроса, идентификатор кэшированного ресурса, сообщается браузером серверу.
Поля, используемые для сопряжения:
- If-Modified-Since и Last-Modified
- Etags и If-None-Match
Сегодня мы сосредоточимся на механизме кэширования браузера.Мы знаем, что кэширование браузера обычно предназначено для статических ресурсов, таких как js, css, изображения и т. д., поэтому наш пример ниже основан на файле javascript a.js. Помимо теоретической обработки, мы запускаем реальную сцену и понемногу улучшаем механизм кеширования, думаю, так всем будет легче понять.
Сделайте некоторые соглашения, чтобы облегчить будущие сравнения.
- a.js имеет размер 10 КБ.
- Соглашение о заголовке запроса: 1 КБ.
- Соглашение о заголовке ответа: 1 КБ.
оригинальная модель
- Браузер запрашивает статический ресурс a.js. (Заголовок запроса: 1 КБ)
- Сервер считывает файл a.js с диска и возвращает его браузеру. (10 КБ (a.js) + 1 КБ (заголовки ответов) = 11 КБ).
- Браузер снова запрашивает, и сервер перечитывает файл a.js на диске и возвращает его браузеру.
- так цикл. .
При круговом обходе трафик составляет 10 (a.js) + 1 (заголовок запроса) + 1 (заголовок ответа) = 12 КБ.
Доступ 10, поток составляет около 12 * 10 = 120 КБ.
Итак, трафик связан с количеством посещений:
L(трафик) = N(посещения) * 12.
Недостатки этого метода очевидны:
- Пустой пользовательский трафик.
- Пустая трата ресурсов сервера, сервер должен прочитать файл на диске, а затем отправить файл в браузер.
- Браузер должен дождаться загрузки и выполнения a.js перед рендерингом страницы, что влияет на взаимодействие с пользователем.
Время выполнения js намного быстрее, чем время загрузки.Если время загрузки можно оптимизировать, пользовательский опыт будет значительно улучшен.
Браузер добавляет механизм кэширования
- Браузер запрашивает a.js в первый раз и кэширует a.js на локальный диск. (1+10+1 = 12 КБ)
- Браузер снова запрашивает a.js, переходит напрямую в кеш браузера (200, из кеша) и больше не инициирует запрос к серверу. (0 КБ)
- ...
При первом посещении трафик составляет 1+10+1 = 12 КБ. Второй визит, трафик 0. . . . 10000-е посещение, трафик по-прежнему 0.
Таким образом, трафик никак не связан с количеством посещений:
L(поток) = 12 КБ.
преимущество:
- Сильно снижает пропускную способность.
- Поскольку время загрузки a.js сокращается, соответственно улучшается взаимодействие с пользователем.
Недостатки: Когда на сервере обновляется a.js, браузер не может это воспринять и не может получить последние ресурсы js.
Сервер и браузер договариваются о сроке действия ресурса.
Сервер и браузер согласовывают время истечения срока действия файла, которое контролируется полем Expires.Время представляет собой стандартное время в формате GMT, например пятница, 01 января 1990 г., 00:00:00 по Гринвичу.
- Браузер впервые запрашивает статический ресурс a.js. (1 КБ)
- Сервер отправляет браузеру время истечения срока действия кэша a.js и a.js (истекает: понедельник, 26 сентября 2018 г., 05:00:00 по Гринвичу). (10+1=11КБ)
Сервер говорит браузеру: вы кешируете файл a.js, который я вам отправил, не беспокойте меня больше запросами до 5:00 26 сентября 2018 года и просто используйте свой собственный кешированный файл a.js.
- Браузер получает a.js и запоминает время истечения.
- До 5:00 26 сентября 2018 года, если браузер снова запрашивает a.js, он больше не будет запрашивать сервер и будет напрямую использовать последний кешированный файл a.js. (0 КБ)
- В 5:01 26 сентября 2018 года браузер запрашивает a.js и обнаруживает, что время кэширования a.js истекло, поэтому он больше не использует локальный кеш, а запрашивает сервер, и сервер перечитывает disk файл a.js , верните его в браузер и сообщите браузеру новое время истечения срока действия. (1+10+1=12 КБ).
- так туда и обратно. . .
Этот способ имеет большие улучшения по сравнению с предыдущим способом:
- В течение срока действия он экономит много трафика для пользователей.
- Снижает нагрузку на сервер, связанную с повторным чтением файлов с диска.
- После истечения срока действия кеша можно получить последний файл a.js.
Недостатки:
- По истечении срока действия кеша сервер снова прочитает файл a.js и вернет его в браузер независимо от того, изменился ли a.js.
Сервер сообщает браузеру, когда ресурс был изменен в последний раз.
Чтобы решить проблему предыдущего решения, сервер и браузер согласовали и сформулировали решение.Каждый раз, когда сервер возвращает a.js, он также сообщает браузеру время последней модификации a.js на сервере Last- Модифицированный (стандартный формат GMT).
-
Браузер обращается к файлу a.js. (1 КБ)
-
Когда сервер возвращает a.js, сообщите браузеру файл a.js. (10+1=11 КБ) Время последней модификации на сервере Last-Modified (стандартный формат GMT) и время истечения кэша Expires (стандартный формат GMT)
-
Когда срок действия a.js истекает, браузер запрашивает сервер с If-Modified-Since (равным Last-Modified последнего запроса). (1 КБ)
-
Сервер сравнивает время Last-Modified в заголовке запроса со временем последнего изменения a.js на сервере:
- Если он непротиворечив, сообщите браузеру: вы можете продолжать использовать локальный кеш (304). На данный момент сервер больше не возвращает файл a.js. (1 КБ)
- Если он несовместим, сервер считывает файл a.js на диске и возвращает его в браузер, и в то же время сообщает браузеру время последней модификации a.js Last-Modified и время истечения срока действия Expires. (1+10=11КБ)
- так туда и обратно.
Эта схема дополнительно оптимизирована по сравнению с предыдущей схемой:
- По истечении срока действия кеша сервер обнаруживает, что если файл не изменился, он больше не отправляет a.js в браузер, экономя 10 КБ трафика.
- По истечении срока действия кеша сервер обнаруживает, что файл изменился, и отправляет браузеру последние файлы a.js, а браузер может получить последние файлы a.js.
недостаток:
- Контроль срока действия Expires нестабилен, поскольку браузер может изменять время по своему желанию, что приводит к неточному использованию кеша.
- Срок действия Last-Modified может быть точным только до секунды.
Есть две проблемы с точностью до секунды:
- 1. Если a.js меняется часто в течение одной секунды, и сервер не устанавливает кеш для a.js, то каждый раз, когда браузер обращается к a.js, он будет запрашивать сервер, в это время сервер сравнивает последнюю отправленную модификацию Обнаружено, что время и время последней модификации a.js совпадают (поскольку оно с точностью до секунды), поэтому оно возвращается в браузер, чтобы продолжить использовать локально кэшированное сообщение (304 ), а на самом деле a.js на сервере меняли много раз. Так что в этом случае браузер не может получить последний файл a.js.
- 2. Если a.js был изменен на сервере, но его фактическое содержимое вообще не изменилось, он вернет a.js в браузер, поскольку время последнего изменения не совпадает.
Продолжать улучшать, увеличивать относительный контроль времени, внедрять Cache-Contorl
Чтобы быть совместимым с браузерами, которые уже реализовали вышеуказанную схему и добавили новую схему кэширования, сервер не только сообщает браузеру Expires , но также сообщает браузеру относительное время Cache-Control: max-age=10 секунд. Это означает, что в течение 10 секунд используйте ресурсы a.js, кэшированные в браузере.
Браузер сначала проверяет Cache-Control, и если он есть, Cache-Control превалирует, игнорируя Expires. Если нет Cache-Control, преобладает Expires.
Продолжайте совершенствоваться, увеличивайте сравнение содержимого файлов, вводите Etag
Чтобы решить проблему, связанную с тем, что время модификации файла может быть с точностью до секунд, мы представили серверу заголовок ответа Etag, и Etag менялся только при изменении содержимого a.js. Содержимое не изменилось, и Etag не изменился, можно понять, что Etag — это уникальный идентификатор содержимого файла. При этом вводится соответствующий заголовок запроса If-None-Match.Каждый раз, когда браузер запрашивает сервер, включается поле If-None-Match.Значением этого поля является значение, возвращаемое сервером браузеру когда в последний раз запрашивался a.js.
- Браузер запрашивает a.js.
- Сервер возвращает a.js и в то же время сообщает браузеру об истечении абсолютного времени (Expires) и относительного времени (Cache-Control: max-age=10), а также времени последней модификации a.js Last -Изменено, и Etag a.js.
- В течение 10 секунд браузер снова запрашивает a.js, больше не запрашивает сервер и напрямую использует локальный кеш.
- Через 11 секунд браузер снова запрашивает a.js, запрашивая у сервера время последней модификации If-Modified-Since и последнее значение Etag If-None-Match.
- Сервер получает If-Modified-Since и Etag от браузера и находит If-None-Match, затем сравнивает If-None-Match со значением Etag a.js, игнорируя сравнение If-Modified-Since.
- Если содержимое файла a.js не изменилось, Etag и If-None-Match согласованы, и сервер сообщает браузеру, что нужно продолжать использовать локальный кеш (304).
- так туда и обратно.
законченный?
Это конец? Да, механизм кэширования http такой, но проблема все же есть:
Браузер не может активно знать, что ресурс a.js на сервере изменился.
Независимо от Expires или Cache-Control, они могут только контролировать, истекает ли срок действия кеша, но до истечения срока действия кеша браузер не может знать, изменились ли ресурсы на сервере. Только по истечении срока действия кеша браузер отправляет запрос на сервер.
Окончательное предложение
Вы можете представить сценарий, в котором мы используем a.js.Обычно мы вводим URL-адрес и получаем доступ к html-файлу, который вводит js и css в html-файл. , изображения и другие ресурсы.
Итак, давайте проделаем несколько трюков с html.
Мы не допускаем кеширования html-файлов, и каждый раз при доступе к html запрашивается сервер. Таким образом, браузер может каждый раз получать последний html-ресурс.
Когда содержимое a.js будет обновлено, давайте изменим номер версии a.js в html.
- Первый визит в html
<script src="http://test.com/a.js?version=0.0.1"></script>
-
Браузер загружает файл a.js версии 0.0.1.
-
Браузер снова обращается к html и обнаруживает, что это все еще файл a.js версии 0.0.1, а затем использует локальный кеш.
-
Однажды a.js изменился, и наш html-файл соответственно изменился следующим образом:
<script src="http://test.com/a.js?version=0.0.2"></script>
- Браузер снова обращается к html и обнаруживает, что [test.com/Ah. Это все? Вер SiO…a.js.
- так туда и обратно.
Таким образом, путем установки запрета кэширования html и изменения пути к ресурсу, когда html ссылается на изменение содержимого ресурса, решается проблема невозможности вовремя узнать об обновлениях ресурсов.
Конечно, кроме номера версии его можно отличить еще и по значению MD5hash. Такие как
<script src="http://test.com/a.【hash值】.js"></script>
Если вы используете webpack для упаковки, с этим можно легко справиться с помощью плагинов.
Кроме этого
В дополнение к установке относительного времени истечения срока действия max-age для Cache-Control также можно установить следующие значения:
- public, ресурс может кэшироваться промежуточными серверами.
Когда браузер запрашивает сервер, если время кэширования не истекло, промежуточный сервер напрямую возвращает содержимое браузеру, не запрашивая исходный сервер.
- private, ресурсы не могут кэшироваться промежуточными прокси-серверами.
Когда браузер запрашивает сервер, промежуточный сервер должен прозрачно передать запрос браузера на сервер.
- no-cache браузер не выполняет проверку кеша.
При каждом доступе к ресурсу браузер должен запрашивать у сервера, если файл не изменился, сервер просто говорит браузеру продолжать использовать кеш (304).
- No-store, ни браузеры, ни промежуточные прокси-серверы не могут кэшировать ресурсы.
При каждом доступе к ресурсу браузер должен запрашивать сервер, и сервер не проверяет, изменился ли файл, а напрямую возвращает полный ресурс.
- must-revalidate, может кэшироваться, но должен быть подтвержден исходным сервером перед использованием.
- proxy-revalidate, который требует, чтобы сервер кеша подтверждал исходный сервер для кэшированного ресурса.
- s-maxage: максимальное время кэш-сервера для кэширования ресурса.
Cache-Control обеспечивает более точное управление кешем, включая управление кешем для кэширующих прокси-серверов.
Статья введена здесь, если вы заинтересованы, вы можете попрактиковаться.