Главния проблем с когото всеки уеб-мастър се сблъсква е, че браузърите обожават да кешират отговорите на сървъра. Това е голям подводен камък, особено в 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 "Забрана кеширане от браузъра"
Публикуване на коментар