
Главния проблем с когото всеки уеб-мастър се сблъсква е, че браузърите обожават да кешират отговорите на сървъра. Това е голям подводен камък, особено в AJAX и най-вече в IE-браузър. Всички браузъри кешират, дори прокси-сървърите, но при IE-браузър кеширането е съпоставимо с болест при заявка под метод GET.
метод GET и PHP
Хайде да спретнем малка демонстрация. Примитивен сървър, където PHP-сценарий връща тъпо времето. Досещате се, че това е файл gettime.php.
<?php
/*
* Сценарий, показващ текущото време
*/
//header("Content-type: text/plain; charset=utf-8");
//header("Current time: ". date("r"));
echo date('H:i:s');
По ред на браузърите правим следните действия.
- Заявка към файл gettime.php;
- Крачка назад в историята;
- Връщане обратно;
- Презареждане - F5;

Какво става на практика?
Заявка към файл gettime.php, печати в браузъра текущото време. Крачка назад в историята (оранжевата стрелка, сочеща наляво) и последвало връщане в текущия прозорец ни показва същото време. Няма изменение. Ако презаредим страницата - получаваме ново време, но ако пак прегледаме историята, то не се променя. И така с браузър Opera, Firefox и дори IE-9. Всички кешират!
Нека прихванем заглавките. А най-интересните са:
http://localhost/ajax/gettime.php GET /ajax/gettime.php HTTP/1.1 Host: localhost ... HTTP/1.1 200 OK Date: Sat, 08 Jun 2013 17:50:33 GMT Server: Apache/2.2.14 (Ubuntu) X-Powered-By: PHP/5.4.15-1~lucid+1 ... Content-Type: text/htmlВидно е, че метода е GET по протокол HTTP/1.1. Става ясно, че браузъра се обръща към PHP сценария, получава текущото време и до тук. То не се мени до нова заявка, а заигравката с историята е показателна, че отговора е кеширан.
метод GET и AJAX
Отлично. Нека усложним задачата и направим нещата под AJAX, за да проследим поведението на изброените браузъри.
xmlhttprequest.js е функцията, която връща обект XMLHttpRequest.
/*
** Функцията връща обект XMLHttpRequest
*/
function getXmlHttpRequest()
{
if (window.XMLHttpRequest)
{
try
{
return new XMLHttpRequest();
}
catch (e){}
}
else if (window.ActiveXObject)
{
try
{
return new ActiveXObject('Msxml2.XMLHTTP');
} catch (e){}
try
{
return new ActiveXObject('Microsoft.XMLHTTP');
}
catch (e){}
}
return null;
Тази функция ще зацепим в индекс файла - index.html. Ето и него за финална сглобка на сайта.<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>кеширане на заявка под метод GET</title>
<script type="text/javascript" src="xmlhttprequest.js"></script>
<script type="text/javascript">
// заявка на данни
function showServerTime()
{
var req = getXmlHttpRequest();
req.onreadystatechange = function()
{
if (req.readyState != 4) return;
var time = document.getElementById("time");
time.firstChild.nodeValue = req.responseText;
}
req.open("GET", "gettime.php", true);
req.send(null);
}
// автостарт
window.onload = function()
{
setInterval("showServerTime()", 1000);
}
</script>
</head>
<body>
<p>часовник <span id="time"> </span></p>
</body>
</html>
еквивалент на showServerTime()function showServerTime(){
var req = getXmlHttpRequest();
req.open("GET", "gettime.php", true);
req.onreadystatechange = function(){
if (req.readyState === XMLHttpRequest.DONE && req.status === 200){
var time = document.getElementById("time");
time.innerHTML = req.responseText;
}
}
req.send();
}
И разбира се правим заявка към индекса. На което Firefox 20.0, Chromium 25.0.1364.160, Opera 9.80 - linux версии честно показват часовника. Той тик-так-а. Отлично на функция setInterval и можем да отдъхнем, че браузърите са забравили да кешират. Тоест, отново чрез javascript се обръщаме към сървъра по метод GET, асинхронно. Получаваме времето и го пъхаме между таг-ове span на страницата. 
Нека продължим. Откриваме Explorer9 9.0.5 под Windows 7 64-bit бла бла бла и хоп, не работи. Замръзване!

Към спънатия браузър се добави някаква стара Windows-версия на Opera. По-важното е, че може да ви се пръсне главата от мислене, защо в някои браузъри часовникът не работи. Скриптът е изряден и проблема остава в кеширането.
Смело може да се каже, че Windows-версия на Opera и Explorer9 честно са кеширали отговора и повече не се интересуват от измененията настъпили на сървъра. Тъпо се обръщат към кеша и четат значението съхранено там. Firefox в това отношение работи по-интелигентно и там кеширането става по желание на програмиста. Как ние можем да фиксираме това?
PHP забрана на кеширане
За съжаление много уеб-майстори не умеят това и тъпо преписват код, когото смело може да се нарече лайнокод. Същите дори не си правят труда, да видят ефективността на кода. Забранява ли въобще кеширането. Връх на невежеството е следния код:
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); //Дата в миналото
header("Last-Modified: ".gmdate("D, d M Y H:i:s")."GMT");
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header("Pragma: no-cache"); // HTTP/1.1
Най-забавното е, че този код не работи. Добавяме го в gettime.php и рестартираме Explorer9. Никаква промяна с часовника, замръзва както преди.Заглавка Expires по идея трябва да определи дата на актуалността на документа. Но защо всички тъпо преписват Mon, 26 Jul 1997 05:00:00 GMT? Наберете тази дата като ключова фраза в търсачката на Google и ще понесете огромна доза потрес, на колко сайта се намира тя.
Този код е наследство от хелпа на PHP версия 3 и неговият автор в ден преди приведената дата е търсил начин как да забрани кеширането от браузъра. Той е смятал, че като върне един ден назад в миналото това ще работи. Днес сме 2013г, а PHP е 5.4 версия. Така че това е тъпня. Смело може да прочетем глава 13 на RFC2616, за да разберем замисъла на кеширането и Expires. С думи прости отсичаме тази заглавка.
Заглавка Last-Modified показва датата на изменение на документа, считайки че браузърите могат да четат това. Вероятно през 1997г това е било нормално, но днес това е загубило своето значение и смело може да се заяви, че спъвате работата на паяците и после има да се чудите защо не ви обичат. Отсичаме я.
Заглавка Pragma: no-cache. Наполеон, когато отстъпвал от опожарена Москва, този метод вече бил остарял. Този код е ерата на HTTP/1.0 и на днешен ден на всички браузъри им е през фара. В киреча!
Остава една заглавка - Cache-Control. И тя действително контролира кеширането. За съжаление тя има около десетина възможни значения. Сега ще я приведем в боен вид и ще компенсираме Last-Modified.
Аплодисменти за gettime.php и елегантния му вид.
<?php
/*
* Сценарий, показващ текущото време
*/
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0"); // HTTP/1.1
echo date('H:i:s');
max-age и Expires е едно и също (поглед в снифера на заглавки). Най-главното е no-store и no-cache. no-store означава лични данни да не съхранява на локалния диск и той отсича кеширането в браузъра, а no-cache командва прокси-сървърите.
Рестартираме Explorer9 и о чудеса, часовникът тик-так-а!
Apache забрана на кеширането
Забраната за кеширане от браузъра може да се възложи на Apache. При всяка заявка той ще изпраща тази заглавки и по този начин няма да се чудите как да го постигате из документите на сайта ви. Досещате се че дойде ред на файл .htaccess от първата снимка горе.
# compiled modules enabled in apache on Debian # user@machine:~$ /usr/sbin/apache2 -l # <?php echo `/usr/sbin/apache2 -l`; ############################################### # loaded modules enabled in apache on Debian # user@machine:~$ ls /etc/apache2/mods-enabled/ ############################################### # list of disabled modules in apache on Debian # ls /etc/apache2/mods-available/ ############################################### # enable mod_headers.c on Debian # sudo a2enmod headers # sudo /etc/init.d/apache2 reload ############################################### # enable mod_expires.c on Debian # sudo a2enmod expires # sudo /etc/init.d/apache2 reload ############################################### # header Cache-Control ############################################### <ifModule mod_headers.c> Header set Cache-Control "no-store, no-cache" </ifModule> # header Expires ############################################### <ifModule mod_expires.c> ExpiresActive On ExpiresDefault "now" </ifModule>Коректната работа на приведения .htaccess-файл за Debian базирани системи изисква включени модули mod_expires.c и mod_headers.c. Как се добавят става ясно от коментарите, които съм добавил в началото на файла.

до нови срещи ^.^

0 Response to "Забрана кеширане от браузъра"
Публикуване на коментар