Как запретить браузеру отдавать кэш на http запрос
по соображениям безопасности мы не хотим, чтобы определенные страницы в нашем приложении кэшировались,никогда, веб-браузером. Это должно работать по крайней мере для следующих браузеров:
- Internet Explorer 6+
- Firefox 1.5+
- сафари 3+
- Opera 9+
- Chrome
наши требование пришло из теста безопасности. После выхода с нашего сайта вы можете нажать кнопку "назад" и просмотреть кэшированные страницы.
правильный минимальный набор заголовков, который работает во всех упомянутых клиентов (и прокси):
с другой стороны, если сервер автоматически включает действительное Date заголовок, тогда вы можете теоретически опустить Cache-Control тоже и положиться на Expires только.
но это может не сработать, если, например, пользователь манипулирует датой операционной системы, и клиентское программное обеспечение полагается на нее.
использование сервлета Java или узла.js:
использование Ruby on Rails или Python/Flask:
Использование Python / Django:
Использование Python / Pyramid:
Использование Google Go:
(Эй, все: пожалуйста, не просто бездумно копировать и вставлять все заголовки, которые вы можете найти)
модель свежести (раздел 4.2) не обязательно применяется к механизмам истории. То есть механизм истории может отображать предыдущее представление, даже если оно истекло.
Back должен вернуться во времени (к тому времени, когда пользователь был logged in). Он не переходит к ранее открытому URL-адресу.
вы никогда надо:
- с заголовками кэша - он вообще не работает. Абсолютно бесполезный.
- post-check / pre-check - это директива IE-only, которая применяется только к cachable ресурсы.
- отправка одного и того же заголовка дважды или в дюжине частей. Некоторые фрагменты PHP фактически заменяют предыдущие заголовки, в результате чего отправляется только последний.
если вы хотите, вы можете добавить:
как заявил porneL, вы хотите не деактивировать кэш, а деактивировать буфер истории. Различные браузеры имеют свои собственные тонкие способы отключения буфера истории.
в Chrome (v28.0.1500.95 м) мы можем сделать это только Cache-Control: no-store .
в FireFox (v23.0.1) любой из них будет работать:
в Safari (v5.1.7, 7534.57.2) любой из них будет работать:
Cache-Control: no-store
в html
In IE8 (v8.0.6001.18702 IC) любой из них будет работать:
Cache-Control: must-revalidate, max-age=0
Cache-Control: must-revalidate
Expires: 0
Cache-Control: must-revalidate
Expires: Sat, 12 Oct 1991 05:00:00 GMT
ниже показаны необработанные журналы моего тесты:
Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
Pragma: no-cache
Vary: *
Fail: Opera 12.15
успех: Chrome 28, FireFox 23, IE8, Safari 5.1.7
Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
Fail: Opera 12.15
Успех: Chrome 28, FireFox 23, IE8, Safari 5.1.7
Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
Pragma: no-cache
Vary: *
Fail: Safari 5.1.7, Opera 12.15
успех: Chrome 28, FireFox 23, IE8
Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
Fail: Safari 5.1.7, Opera 12.15
Успех: Chrome 28, FireFox 23, ИЕ8
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
Pragma: no-cache
Vary: *
Сбой: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
успех: IE8
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
Сбой: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
успех: ИЕ8
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
Pragma: no-cache
Vary: *
Сбой: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
успех: IE8
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
Сбой: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
успех: ИЕ8
Cache-Control: no-store
Fail: Safari 5.1.7, Opera 12.15
успех: Chrome 28, FireFox 23, IE8
Cache-Control: no-store
Fail: Opera 12.15
успех: Chrome 28, FireFox 23, IE8, Safari 5.1.7
Cache-Control: no-cache
Сбой: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
успех: ИЕ8
Vary: *
сбой: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
успех: ничего
Pragma: no-cache
сбой: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
успех: ничего
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
Сбой: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
успех: IE8
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
Pragma: no-cache
Vary: *
Сбой: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
успех: IE8
Cache-Control: must-revalidate, max-age=0
Сбой: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
успех: ИЕ8
Cache-Control: must-revalidate
Expires: 0
Сбой: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
успех: IE8
Cache-Control: must-revalidate
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Сбой: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
успех: IE8
Cache-Control: private, must-revalidate, proxy-revalidate, s-maxage=0
Pragma: no-cache
Vary: *
Сбой: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
успех: ничего
Cache-Control: private, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
сбой: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
успех: ничего
Cache-Control: private, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
сбой: Chrome 28, FireFox 23, IE8, Сафари 5.1.7, Опера 12.15
успех: ничего
Vary: *
Сбой: Chrome 28, Safari 5.1.7, Opera 12.15
успех: FireFox 23, IE8
Pragma: no-cache
Сбой: Chrome 28, Safari 5.1.7, Opera 12.15
успех: FireFox 23, IE8
Cache-Control: no-cache
Сбой: Chrome 28, Safari 5.1.7, Opera 12.15
успех: FireFox 23, IE8
Cache-Control: private, no-cache, max-age=0, proxy-revalidate, s-maxage=0
Сбой: Chrome 28, Safari 5.1.7, Opera 12.15
успех: FireFox 23, IE8
Cache-Control: private, no-cache, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
Pragma: no-cache
Vary: *
Сбой: Chrome 28, Safari 5.1.7, Opera 12.15
Успех: FireFox 23, ИЕ8
Cache-Control: private, no-cache, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
Сбой: Chrome 28, Safari 5.1.7, Opera 12.15
успех: FireFox 23, IE8
Cache-Control: must-revalidate
сбой: Chrome 28, FireFox 23, IE8, Safari 5.1.7
Успех: Опера 12.15
Cache-Control: private, must-revalidate, proxy-revalidate, s-maxage=0
сбой: Chrome 28, FireFox 23, IE8, Сафари 5.1.7
Успех: Опера 12.15
Cache-Control: must-revalidate, max-age=0
Сбой: Chrome 28, FireFox 23, Safari 5.1.7
успех: IE8, Opera 12.15
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
Сбой: Chrome 28, Safari 5.1.7
успех: FireFox 23, IE8, Opera 12.15
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
Pragma: no-cache
Vary: *
Сбой: Chrome 28, Safari 5.1.7
успех: FireFox 23, IE8, Opera 12.15
Cache-Control: no-store
Fail: Opera 12.15
успех: Chrome 28, FireFox 23, IE8, Safari 5.1.7
Cache-Control: private, no-cache, no-store, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
Pragma: no-cache
Vary: *
Fail: Opera 12.15
успех: Chrome 28, FireFox 23, IE8, Safari 5.1.7
Cache-Control: private, no-cache, no-store, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
Fail: Opera 12.15
успех: Chrome 28, FireFox 23, IE8, Safari 5.1.7
Cache-Control: private, no-cache
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
Сбой: Chrome 28, Safari 5.1.7, Opera 12.15
успех: FireFox 23, IE8
Cache-Control: must-revalidate
Expires: 0
Сбой: Chrome 28, FireFox 23, Safari 5.1.7,
успех: IE8, Opera 12.15
Cache-Control: must-revalidate
Expires: Sat, 12 Oct 1991 05:00:00 GMT
незачет: Chrome 28, FireFox 23, Safari 5.1.7,
успех: IE8, Opera 12.15
Cache-Control: private, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
Сбой: Chrome 28, FireFox 23, Safari 5.1.7,
успех: IE8, Opera 12.15
Cache-Control: private, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Сбой: Chrome 28, FireFox 23, Safari 5.1.7,
успех: IE8, Opera 12.15
Cache-Control: private, must-revalidate
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
Сбой: Chrome 28, Safari 5.1.7
успех: FireFox 23, IE8, Opera 12.15
Cache-Control: no-store, must-revalidate
Fail: нет
успех: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
Я нашел в интернете.config route полезен (пытался добавить его в ответ, но, похоже, не был принят, поэтому разместите здесь)
и вот экспресс / узел.JS способ сделать то же самое:
после долгих исследований и тестирования я обнаружил, что мне действительно нужны только два заголовка:
на IE6-8, FF1.5-3.5, Chrome 2-3, Safari 4 и Opera 9-10, эти заголовки заставили страницу запрашиваться с сервера при нажатии на ссылку на страницу или поместить URL-адрес непосредственно в адресной строке. Это охватывает около 99% всех браузеров, используемых с января ' 10.
после небольшого исследования, мы придумали следующий список заголовков, которые, казалось, покрывали большинство браузеров:
- истекает: Пн, 26 июля 1997 05:00: 00 GMT
- Кэш-Контроля: нет-кэш, частного, должен-revalidate, max-stale=0, post-check=0, pre-check=0 no-store
- Прагма: нет-кэш
использование заголовка pragma в ответе-это история жен. RFC2616 определяет его только как заголовок запроса
я попробовал "принятый" ответ для PHP, который не работал для меня. Затем я провел небольшое исследование, нашел небольшой вариант, протестировал его и это сработало. Вот это:
это должно сработать. Проблема заключалась в том, что при установке одной и той же части заголовка дважды, если false не отправляется в качестве второго аргумента функции заголовка, функция заголовка просто перезапишет предыдущий header() звонок. Итак, при установке Cache-Control , например, если вы не хотите помещать все аргументы в один header() вызов функции, он должен сделать что-то вроде этого:
посмотреть более полную документацию здесь.
в IE6 есть ошибка
содержимое с "Content-Encoding: gzip" всегда кэшируется, даже если вы используете "Cache-Control: no-cache".
вы можете отключить сжатие gzip для пользователей IE6 (проверьте агент пользователя для "MSIE 6")
эти директивы не уменьшают никакой риск для безопасности. Они действительно предназначены для того, чтобы заставить UA обновлять изменчивую информацию, а не удерживать UA от сохранения информации. См.этот же вопрос. По крайней мере, нет никакой гарантии, что все маршрутизаторы, прокси и т. д. также не будет игнорировать директивы кэширования.
на более положительной ноте, политики в отношении физического доступа к компьютерам, установки программного обеспечения и тому подобное поставят вам мили опережает большинство фирм в плане безопасности. Если потребители этой информации являются представителями общественности, единственное, что вы действительно можете сделать, это помочь им понять, что как только информация попадает на их машину, эта машина их ответственность, не твоя.
на документация PHP для функции заголовка имеет довольно полный пример (предоставлено третьим лицом):
Если вы столкнулись с проблемами загрузки с IE6-IE8 через SSL и cache:no-cache header (и аналогичные значения) с файлами MS Office,вы можете использовать cache: private, no-store header и return file по запросу POST. Это работает.
в моем случае я исправляю проблему в chrome с помощью этого
где мне нужно очистить содержимое данных формы previus, когда пользователи нажимают кнопку назад по соображениям безопасности
затем зарегистрировать его в Startup.cs
убедитесь, что вы добавить это где-то после
У меня были лучшие и наиболее последовательные результаты во всех браузерах, установив Pragma: no-cache
принятый ответ, похоже, не работает для IIS7+, учитывая большое количество вопросов о заголовках кэша, которые не отправляются в II7:
принятый ответ Правильный, в котором заголовки должны быть установлены, но не в том, как они должны быть установлены. Этот способ работает с IIS7:
первая строка задает Cache-control to no-cache , а вторая строка добавляет другие атрибуты no-store, must-revalidate
кроме того, просто для хорошей меры, убедитесь, что вы сбросили ExpiresDefault в своем .htaccess файл, если вы используете это для включения кэширования.
после этого вы можете использовать ExpiresByType установить конкретные значения для файлов, которые вы хотите кэшировать:
это также может пригодиться, если ваши динамические файлы, например php и т. д. кэшируются браузером, и вы не можете понять, почему. Проверка ExpiresDefault .
I have a php site running in cloud server.When ever i add new files css, js or images the browser is loading the same old js, css and image files stored in cache.
My site has a doctype and meta tag as below
Because of the above doctype and meta code am i loading the same files cached in browser instead of new one
No Cache in all Browsers . You can also do a ?randomGeneratedNumber on the files you dont want to be cached.
6 Answers 6
Except for "max-age=0", those are the headers sent by PHP without specifying the above in my installation.. It seems PHP tries to prevent browser caching by default.
I have a WordPress plugin that sends an alternate theme to old versions of Internet Explorer and it was getting badly tripped up on some caching systems. This post came up on my first Google search. Well played.
Do keep in mind that this cannot be embedded inside of html; this should be at the very top of the page.
Note: If you use session_start() afterwards, it will overwrite your header with Cache-Control: private, max-age=10800, pre-check=10800 because 180 minutes is the default value of session.cache_expire . If you can not avoid starting the session, but you need to disable the cache use session_cache_limiter('private');session_cache_expire(0); .
@thdoan The second parameter of header function is a boolean for replace. The optional replace parameter indicates whether the header should replace a previous similar header, or add a second header of the same type.
Here, if you want to control it through HTML: do like below Option 1:
And if you want to control it through PHP: do it like below Option 2:
AND Option 2 IS ALWAYS BETTER in order to avoid proxy based caching issue.
You can try this:
Hopefully it will help prevent Cache, if any!
just the first line should suffice perfectly. 5th line is actually plain wrong and has nothing to do in a server response (it is a request header). sixth line will have no effect whatsovever. i could go on.
The shotgun approach: throw everything at the wall, hope something sticks. As per my comment on the question itself, I can highly recommend grabbing a copy of HTTP: The Definitive Guide and reading the chapter on Caching. Also the RFCs, but reading those is a distinct skill. ("Connection: close" is a hilarious foot-shot to include, disabling efficient pipelining of requests, or will do nothing, but I suspect PHP might actually let that through.)
I had problem with caching my css files. Setting headers in PHP didn't help me (perhaps because the headers would need to be set in the stylesheet file instead of the page linking to it?).
The solution:
Append timestamp as the query part of the URI for the linked file.
(Can be used for css, js, images etc.)
For production (where caching is mostly a good thing):
Or combination of these two:
EDIT:
Or prettier combination of those two:
Arbitrary versions, current timestamps (defeating caching entirely)… but not the one thing that actually makes sense and work, regardless of a "debugging" flag or not. Why aren't you using the actual mtime of the file? Then you'd literally never need to update the PHP, and caches wouldn't become completely and fantastically useless. Or just deliver your statics with a properly configured HTTP server like Nginx or Apache that sets a proper Last-Modified and ETag. Similarly, that type of "debugging" flag already exists… in the browser. (Disable caches, refresh without cache, empty caches, …)
Prevent browser cache is not a good idea depending on the case. Looking for a solution I found solutions like this:
the problem here is that if the file is overwritten during an update on the server, which is my scenario, the cache is ignored because timestamp is modified even the content of the file is the same.
I use this solution to force browser to download assets only if its content is modified:
Yikes! This would be terrible for performance and scalability to always be loading all of your CSS/JS files in the main thread to check their size/hash.
@Dalin Before you cry the tears of Gentoo ricer (a Linux distro known for "going fast" by being excessively compiled from source and architecture-tuned) I'd clock a stat call. Without filesystem cache, 16ns, tops? With cache, reliably < 8ns. Nanoseconds. And on my system MD5 can process 754 MiB/s without blinking. ( openssl speed md5 ) Combined, a 100KB CSS file would have a combined additional overhead of… 129µs (microseconds, 0.1295ms) + 8ns (which does not meaningfully contribute to the final number) = 129µs.
Upon further consideration, it blows me over that the only "correct" answer (with lowest maintenance burden, most accurate/reliable behavior) is both the least voted for, and dismissed in a single comment on such flimsy and unrealistic grounds.
You and I probably work on different websites. But I stand by my comment. If there's dozen's of concurrent threads delivering web pages at any point in time, then I think there's better options that you won't even need to question whether it's scalable. hash_file('md5', $deployment_counter) or hash_file('md5', $cache_clear_counter) are the first that come to mind.
Если вы уже понимаете преимущества ЗК, и хотите расширить свои знания, я рекомендую вам обратиться к документации от W3.
Что могут ЗК сделать для вас?
Проще говоря, кэширование позволяет хранить веб-ресурсы на удалённых точках по пути от вашего сервера к пользовательскому браузеру. Браузер тоже хранит у себя кэш, чтобы клиенты не запрашивали у вас постоянно одни и те же ресурсы.
Настройки кэширования веб-трафика крайне важны для посещаемых сайтов. Если вы платите за трафик, получаете доход от электронной коммерции, или просто хотите поддерживать свою репутацию хорошего веб-разработчика, вам нужно разбираться в том, как работает кэширование.
В случае ресурсов вроде логотипа вашей компании, favicon сайта или основных CSS-файлов, которые не меняются от запроса к запросу, можно разрешить запрашивающему хранить копии этих файлов какое-то время. Если бы ваши посетители были детьми на заднем сиденье автомобиля, которые бы всё время спрашивали вас «Мы уже приехали?», то это разрешение было бы сродни ответу «Нет, и нам ехать ещё 20 минут, так что запомните мой ответ».
Уменьшая количество запросов к серверу, вы увеличиваете число запросов, которые он может обработать. Картинки, скрипты и таблицы стилей обычно можно кэшировать в хвост и гриву, а динамически создаваемые страницы (форумы, веб-приложения) обычно не стоит. Если вы беспокоитесь в первую очередь за производительность, весь ваш динамический контент должен быть сведён к минимуму ресурсов AJAX, а остальные ресурсы должны кэшироваться по-максимуму.
Для клиентов и CDN
Исторически настройки кэша относились лишь к браузеру клиента, поэтому не стоит забывать и о них. Но сегодня в связи с распространением сетей доставки контента, CDN, важнее понять, как кэширование работает на промежуточных точках веб-сети.
При правильной настройке, CDN передаёт ваш контент клиентам через самый быстрый и ближайший к нему сервер. Кроме этого, CDN работает буфером между вами и пользователями. Нас интересует процент количества кэшированных запросов – тех запросов, которые CDN обработало, не дёргая наш сервер. В зависимости от трафика и архитектуры этот номер может достигать и 90%, хотя эффект вы заметите и при меньших цифрах. Надо заметить, что при небольшом количестве запросов большая их часть будет отправляться на ваш сервер – поэтому этот процент имеет смысл только вместе с временем кэширования и общей нагрузкой сайта. Но если вы настроите один лишь кэш, а заголовки кэширования будут работать неправильно, итоговые показатели могут даже стать хуже, чем были.
Ваши сервера поставляют контент промежуточным серверам, которые присутствуют в разных регионах.
Кроме кэширования, у CDN есть приятный побочный эффект: если вдруг ваши сервера падают, CDN в некоторых случаях буферизуют запросы так, что пользователи этого могут и не заметить.
Основные заголовки
1. cache-control
Самый главный из всех. Обычно вы задаёте в строке его параметры, нечто вроде:
cache-control: private, max-age=0, no-cache
Эти настройки называются директивы ответа кэша, и они бывают следующие:
Сообщает, не является ли контент предназначенным для конкретного пользователя. Если это так, кэшировать его не нужно.
Сама по себе директива говорит, что этот запрос нужно каждый раз делать заново. Обычно используется заголовок etag, о котором ниже. Веселье начинается, когда вы задаёте имя поля после этой директивы. Тогда кэширующие сервера понимают, что ответ можно кешировать, но при этом надо удалять заданные поля. Это, например, полезно для правильной работы куков. Однако, некоторые старые программы не умеют работать с этим трюком.
Сообщает, что этот ответ не нужно хранить. Удивительно, но факт. Если кэш работает по правилам, он убедится, что никакая из частей запроса не будет храниться. Это нужно для того, чтобы обезопасить всякую чувствительную информацию.
Обычно время жизни ресурса задаётся через expires, но если вам надо быть более конкретным, можно задать max-age в секундах. И эта директива имеет преимущество над expires.
Немного похоже на предыдущую, однако s здесь означает shared cache, и нужна для CDN. Эта директива имеет преимущество над max-age и expires, когда речь идёт о CDN-серверах.
Говорит, что каждый запрос нужно делать заново, и ни при каких условиях не предоставлять пользователю закешированный контент. Имеет преимущество над всеми другими директивами, которые разрешают кэширование. В основном используется в некоторых особенных протоколах (к примеру, денежные переводы).
Некоторые прокси умеют сжимать и конвертировать контент для ускорения работы. Эта директива запрещает подобное поведение.
Примерно то же, что must-revalidate, но для промежуточных CDN-серверов. Почему её не назвали s-mustrevalidate? Кто его знает. Смысл в том, что проверять, не обновился ли контент, нужно для каждого нового пользователя только один раз.
2. expires
Изначально это был стандартный метод определения того, когда устаревает ресурс. Сегодня max-age и s-maxage имеют над ним преимущество, но всегда полезно задавать этот заголовок в целях обратной совместимости.
Задав дату, отстоящую более, чем на год, вы нарушите спецификацию заголовка.
3. etag
Сокращение от entity-tag. Это уникальный идентификатор запрашиваемого ресурса – обычно, некий хэш его содержимого, или хэш времени его обновления. В общем, способ клиента запросить у CDN «дай мне ресурс Х, если у него etag отличается от моего».
4. vary
Очень мощная штука. IE в прошлом обрабатывал его неправильно, да и сейчас не совсем корректно справляется. В какой-то момент даже Chrome с ним глючил. По сути, заголовок говорит системам кэширования, какие из заголовков можно использовать для определения того, допустимый ли у них в кэше лежит контент. Если рассматривать кэш как хранилище данных вида ключ-значение, то использование vary добавляет эти значения к ключам.
Часто можно встретить заголовок типа Accept-Encoding, который удостоверяется, что ваши ресурсы, сжатые gzip, будут приняты клиентом. Это здорово сберегает трафик. Кроме этого, настройка
сделает ваш сайт более дружественным к SEO, если вы раздаёте разные HTML/CSS в зависимости от User-Agent. Google заметит эту штучку и Googlebot будет обрабатывать и ваш мобильный контент.
5. pragma
Довольно старая директива, которая умеет делать много чего, что, однако, уже обрабатывается при помощи более современных. Нам более всего интересна форма
что в современных клиентах превращается в
Предостережения
Не все CDN или программы у клиентов работают согласно спецификациям. Если вы занимаетесь веб-разработкой, вам знакома эта проблема. Поэтому перед запуском сервиса всегда надо тестировать его, чтобы убедиться, что всё работает, как нужно.
1. Сжатие
Провайдеры CDN, получающие запрос в gzip в качестве приемлемого сжатия, также должны запрашивать сжатый контент с сервера, или предоставлять клиенту сжатую версию ресурса. Современные CDN умеют проводить сжатие ресурсов самостоятельно.
При тестировании быстродействия серверов CDN нужно учесть, что некоторые настроены так, чтобы проверять наличие у себя как сжатой, так и несжатой версий ресурсов. Эта проверка слегка увеличивает время на реагирование.
2. SSL
А что же с динамическим контентом?
Обычно в этом случае надо задавать cache-control: no-cache, чтобы CDN не кэшировали его. Если вам интересно, как можно немного ускорить и его работу, продолжайте чтение.
Типичный динамический контент
Анализ времени кэширования
Так какое время для хранения ресурсов лучше задавать? Это зависит от количества трафика, размера ресурсов, размера кэша.
Кроме того, надо подумать о главном недостатке кэширования – уменьшении контроля над ресурсами. Если вам надо обновить ресурс мгновенно, у вас будут проблемы, если вы некоторое время назад задали ему время жизни в год. Особенно, если вы задали это время не только для CDN (s-maxage), но и для пользователей (max-age).
Самый длительный промежуток для кэша – год, или 31536000. Но это плохая идея. Это всё равно, что сделать татуировку на лице. Если ваши сервера не выдерживают хотя бы ежедневных запросов от CDN по поводу того, изменился ли ресурс,- пора менять сервера.
Заголовки для статичного контента
Пример настроек кэша для статичного контента с S3. Кэшу рекомендуется хранить ресурс 900 секунд, пользовательским программам – 300 секунд. Последний заголовок говорит о том, какой из CDN обработал запрос.
Одно исключение из заповеди «не кэшируй ресурсы на год», а точнее, один хак, позволяющий обойти проблемы долгого кэша. Вы можете переименовывать ресурс каждый раз, когда выпускаете новую его версию. К его имени может добавляться увеличивающийся номер версии, временной ярлык, хэш.
В следующей таблице отражается потеря времени на кэш. Предполагая, что ресурс получает 500 запросов в минуту, для разных вариантов времени хранения ресурса получаются следующий процент запросов к кэшу:
Время кэширования (мин) | Процент запросов к кэшу | Запросов к оригиналу в час |
1 | 99.8% | 60 |
5 | 99.96% | 12 |
20 | 99.99% | 3 |
60 | 99.997% | 1 |
86400 | 99.9998% |
Какой процент запросов к кэшу вас устроит? Обычно от 60 секунд до 60 минут – нормальное время жизни для ресурса. Для псевдо-динамического контента можно устанавливать время кэширования в промежутке до 60 секунд.
Проверка CDN
Проверяйте, что заголовки проходят через CDN так, как вы этого ожидаете. Обычно CDN вставляет какой-нибудь Х- заголовок, где указывает подробности по данному ресурсу. Вот некоторые инструменты, которые показались мне довольно полезными.
1. Web Inspector
Самый простой метод – правый клик на странице в Chrome, выбрать Inspect Element, перейти на закладку Network и нажать на ресурс HTML. Если это не выбрано по умолчанию, выбрать закладку Headers, чтобы посмотреть все заголовки. Также в Chrome есть возможности задать user agent и не использовать локальный кэш.
2. Charles Proxy
3. cURL
4. hurl.it
Грубо говоря, это cURL с понятным интерфейсом. Можно задавать заголовки и просматривать заголовки ответа и тело ответа.
5. Python и Requests
Requests – библиотека для Python для веб-запросов. С её помощью можно написать автоматизированные тесты для вашего сайта.
Заметки на полях
Теперь, когда вы прочли весь гид, немного замечаний.
Большинство веб-серверов, таких, как Apache и Nginx, делают большую часть работы за вас. Вам придётся работать только с заголовком cache-control. Браузеры обычно настроены на сильное кэширование контента, поэтому вам чаще приходится бороться с излишним кэшированием, нежели наоборот. Обычно вы задаёте некий путь вроде “/static”, который кэшируется какое-то разумное время, например, 300 секунд. Затем надо убедиться, что корневой путь "/" отдаётся с заголовком “cache-control: no-cache”, а лучше перенаправлять пользователя за динамическим контентом прямо на ваши сервера, и оставлять для CDN только то, что лежит в “/static”.
У CDN обычно есть возможность нарушить правила кэширования и кэшировать столько, сколько вам надо, независимо от заголовков. Также они частенько вольно обходятся с протоколами, поэтому так важно тестировать то, что отдают сервера CDN и сравнивать их с заголовками ваших серверов.
За дополнительными материалами по ускорению работы сайта рекомендуем обратиться к документации Mobile Web Performance.
Синтаксис
Инструкции не чувствительны к регистру и имеют необязательный аргумент, который может быть указан как в кавычках, так и без них. Несколько инструкций разделяются запятыми.
Инструкции кеширования для запросов
Расширенные инструкции Cache-Control
Инструкции
Управление кешированием
Управление временем жизни
max-age=
Управление ревалидацией и перезагрузкой
Другие инструкции
no-store Кеш не должен хранить никакую информацию о запросе и ответе no-transform Никакие преобразования не должны применяться к ресурсу. Заголовки Content-Encoding , Content-Range , Content-Type не должны изменяться прокси. Непрозрачный прокси может, например, конвертировать изображения из одного формата в другой для сохранения дискового пространства или уменьшения трафика. Инструкция no-transform запрещает это.
Примеры
Выключение кеширования
Для выключения кеширования возможно добавить следующий заголовок к ответу. Дополнительно см. заголовки Expires и Pragma .
Кеширование статического контента
Для файлов, которые не будут изменяться обычно возможно применить агрессивное кеширование, отослав ответ с заголовком ниже. Например, такой ответ может быть послан для изображений, файлов CSS и JavaScript. Дополнительно см. заголовок Expires .
Различные виды кеширования
Техника кеширования заключается в сохранении копии полученного ресурса для возврата этой копии в ответ на дальнейшие запросы. Запрос на ресурс, уже имеющийся в веб-кеше, перехватывается, и вместо обращения к исходному серверу выполняется загрузка копии из кеша. Таким образом снижается нагрузка на сервер, которому не приходится самому обслуживать всех клиентов, и повышается производительность — кеш ближе к клиенту и ресурс передаётся быстрее. Кеширование является основным источником повышения производительности веб-сайтов. Однако, кеш надо правильно сконфигурировать: ресурсы редко остаются неизменными, так что копию требуется хранить только до того момента, как ресурс изменился, но не дольше.
Существует несколько видов кешей, которые можно разделить на две основные категории: приватные кеши и кеши совместного использования. В кешах совместного использования (shared cache) хранятся копии, которые могут направляться разным пользователям. Приватный кеш (private cache) предназначен для отдельного пользователя. Здесь будет говориться в основном о кешах браузеров и прокси, но существуют также кеши шлюзов, CDN, реверсные прокси кеши и балансировщики нагрузки, разворачиваемые на серверах для повышения надёжности, производительности и масштабируемости веб-сайтов и веб-приложений.
Приватный (private) кеш браузера
Общий (shared) прокси-кеш
Кеш совместного использования — это кеш, который сохраняет ответы, чтобы их потом могли использовать разные пользователи. Например, в локальной сети вашего провайдера или компании, может быть установлен прокси, обслуживающий множество пользователей, чтобы можно было повторно использовать популярные ресурсы, сокращая тем самым сетевой трафик и время ожидания.
Цели кеширования
Первичный ключ состоит из метода запроса и запрашиваемого URI (зачастую используется только URI, поскольку целью кеширования являются только GET-запросы). Вот примеры того, что обычно записывается в кеш:
Ответы на запросы отличные от GET , если есть что-либо, подходящее для использования в качестве ключа кеша.
Управление кеш ированием
Заголовок Cache-control
Полное отсутствие кеширования
В кеше не должно сохраняться ничего — ни по запросам клиента, ни по ответам сервера. Запрос всегда отправляется на сервер, ответ всегда загружается полностью.
Кешировать, но проверять актуальность
Перед тем, как выдать копию, кеш запрашивает исходный сервер на предмет актуальности ресурса.
Приватные (private) и общие (public) кеши
Директива "public" указывает, что ответ можно сохранять в любом кеше. Это бывает полезно, если возникает потребность сохранить страницы с HTTP-аутентификацией, или такими кодами ответа, которые обычно не кешируются. Директива же "private" указывает, что ответ предназначен отдельному пользователю и не должен храниться в кеше совместного использования. В этом случае ответ может сохраняться приватным кешем браузера.
Срок действия (Expiration)
Самой важной здесь является директива "max-age=" — максимальное время, в течение которого ресурс считается "свежим". В отличие от директивы Expires , она привязана к моменту запроса. К неизменяющимся файлам приложения обычно можно применять "агрессивное" кеширование. Примером таких статических файлов могут быть изображения, файлы стилей (CSS) или скриптов (JavaScript).
Подробнее об этом рассказывается в разделе Свежесть ресурса.
Проверка актуальности
При использовании директивы "must-revalidate" кеш обязан проверять статус ресурсов с истёкшим сроком действия. Те копии, что утратили актуальность, использоваться не должны. Подробнее об этом рассказано ниже, в разделе Валидация кеша.
Заголовок Pragma
Свежесть сохранённой копии
Однажды попав в кеш, ресурс, теоретически, может храниться там вечно. Однако, поскольку объем хранилища конечен, записи периодически приходится оттуда удалять. Этот процесс называют вытеснением данных из кеша (cache eviction). Кроме того, ресурсы могут изменяться на сервере, поэтому кеш требуется обновлять. Поскольку HTTP является клиент-серверным протоколом, сервера не могут сами обращаться к кешам и клиентам при изменении ресурса; им необходимо договориться о сроке действия сохранённой копии. До его истечения ресурс считается свежим (fresh), после — устаревшим (stale). Алгоритмы вытеснения отдают предпочтение "свежим" ресурсам. Тем не менее, копия ресурса не удаляется из кеша сразу же по истечении её срока действия; при получении запроса на устаревший ресурс кеш передаёт его дальше с заголовком If-None-Match (en-US) на случай, если копия все ещё актуальна. Если это так, сервер возвращает заголовок 304 Not Modified («не изменялось»), а тело ресурса не посылает, экономя тем самым трафик.
Вот пример того, как протекает этот процесс при использовании совместного кеша прокси:
Срок действия (freshnessLifetime) вычисляется на основании нескольких заголовков. Если задан заголовок "Cache-control: max-age=N", то срок действия равен N. Если его нет, а это бывает очень часто, проверяется заголовок Expires , и, если он есть, то срок действия берётся равным значению заголовка Expires минус значение заголовка Date. Наконец, если нет ни того ни другого, смотрят заголовок Last-Modified. Если он есть, то срок действия равен значению заголовка Date минус значение заголовка Last-modified разделить на 10.
Время устаревания (expirationTime) вычисляется следующим образом:
где responseTime — это время получения ответа по часам браузера, а currentAge — текущий возраст кеша.
Обновление статических ресурсов (Revved resources)
Чем больше ресурсов может быть взято из кеша, тем быстрее сайт реагирует на запросы и тем выше его производительность. Из этих соображений их "срок годности" имеет смысл делать как можно большим. Однако, возникает проблема с ресурсами, которые обновляются редко и нерегулярно. Как раз их кеширование даёт больше всего выгоды, но сильно затрудняет обновление. Такие ресурсы можно найти на любой веб-странице: файлы скриптов (JavaScript) и стилей (CSS) изменяются редко, но уж если это произошло, обновление надо произвести как можно быстрее.
Этот метод имеет дополнительное достоинство: одновременное обновление двух кешированных ресурсов не приводит к ситуации, при которой устаревшая версия одного ресурса используется вместе с новой версией другого. Это очень важно для сайтов с взаимосвязанными файлами стилей CSS или JS-скриптов — связь может возникнуть, например, из-за ссылок на одни и те же элементы HTML-страницы.
Номер версии, добавляемый к статическому ресурсу, не обязательно записывать в виде стандартного номера версии наподобие 1.1.3, или другого возрастающего числового значения. Это может быть что угодно, позволяющее избежать совпадений — например, дата.
Валидация кеша
Валидация кеша запускается при нажатии пользователем кнопки перезагрузки. Кроме того, она может выполняться в ходе обычного просмотра страниц, если кешированный ответ включает заголовок "Cache-control: must-revalidate". Другим фактором являются настройки кеширования браузера — можно потребовать принудительной валидации при каждой загрузке документа.
При истечении срока годности документа он либо проходит валидацию, либо повторно доставляется с сервера. Валидация может выполняться только если на сервере реализован сильный валидатор или слабый валидатор.
Заголовки ETag
Заголовок ответа ETag является непрозрачным для клиентского приложения (агента) значением, которое можно использовать в качестве сильного валидатора. Суть в том, что клиент, например, браузер, не знает, что представляет эта строка и не может предсказать, каким будет её значение. Если в ответе присутствует заголовок ETag , клиент может транслировать его значение через заголовок If-None-Match (en-US) будущих запросов для валидации кешированного ресурса.
Заголовок ответа Last-Modified можно использовать в качестве слабого валидатора. Слабым он считается из-за того, что имеет 1-секундное разрешение. Если в ответе присутствует заголовок Last-Modified , то для валидации кешированного документа клиент может выводить в запросах заголовок If-Modified-Since .
При запросе на валидацию сервер может либо проигнорировать валидацию и послать стандартный ответ 200 OK , либо вернуть ответ 304 Not Modified (с пустым телом), тем самым указывая браузеру взять копию из кеша. В последнем случае в ответ могут входить также заголовки для обновления срока действия кешированного ресурса.
Изменяющиеся ответы
Если кеш получает запрос, который можно удовлетворить сохранённым в кеше ответом с заголовком Vary , то использовать этот ответ можно только при совпадении всех указанных в Vary полей заголовка исходного (сохранённого в кеше) запроса и нового запроса.
Это может быть полезно, например, при динамическом предоставлении контента. При использовании заголовка Vary: User-Agent кеширующие сервера, принимая решение об использовании страницы из кеша, должны учитывать агент пользователя. Так можно избежать ситуации, когда пользователи мобильных устройств по ошибке получат десктопную версию вашего сайта. Вдобавок, это может помочь Google и другим поисковым системам обнаружить мобильную версию страницы, и может также указать им на то, что здесь нет никакой подмены контента с целью поисковой оптимизации (Cloaking).
Поскольку значение заголовка User-Agent различается ("varies") у мобильных и десктопных клиентов, закешированный мобильный контент не будет по ошибке отсылаться пользователям десктопов и наоборот.
Читайте также: