![](https://habrastorage.org/getpro/habr/olpictures/334/6e5/999/3346e5999b4616e955fff88304ba476b.gif)
Одним из неприятных моментов при использовании AJAX – является отсутствие прямых ссылок на динамически сгенерированные страницы или их отдельные части. Здесь кроется и вообще-то концептуальный вопрос – а что, собственно говоря, является в таком подходе страницей – она не имеет некоторого статического представления, каждый раз совершенно другая (не путать с динамической генерацией на сервере), и, фактически, предоставляет пользователю окно в многомерное представление самой себя.
Но все же – допустим, у нас есть простенький, но претенциозный веб-сайт визитка, где по переходам меню AJAX подгружает и выводит контент, а мы хотим дать знакомому по ICQ ссылку на контактную страницу (или любую другую, не суть важно).
Есть два подхода решения проблемы ссылок.
Первый – в каком-то месте страницы указывать текущий нормальный адрес или кнопку получения адреса страницы (такое практикуется на сайтах с видеоконтентом, где выдают прямые ссылки на страницу или плеер). Данный подход не совсем удобен, так как добавление текущей страницы в закладку отличается от стандартного метода и иногда требует от пользователя дополнительных действий, иногда совершенно нетривиальных.
Второй подход – это использовать якоря для генерации ссылок в адресной строке браузера. Данный подход более предпочтительней и более распространен, так как позволяет использовать стандартный подход для добавления в закладки ссылок на страницы, а также при желании позволяет реализовать на AJAX историю навигации по сайту.
При использовании второго подхода ссылки на динамически сгенерированные будут иметь подобный вид: site.ru/#:news, site.ru/#:download или site.ru/#content/blogcategory/4/7
В дальнейшем, при переходе по такой ссылке (к примеру, с закладок) механизм добывания контента страницы реализуется путем определения на клиенте якоря, и подгрузки соответствующего ему контента. В интернете не очень много статей на эту тему. В рунете вообще практически нет.
Одной из проблем данного подхода является первая «холостая загрузка контента».
Для понимания сути проблемы рассмотрим немного более детально механизм перехода по AJAX ссылкам. Как известно, якоря (#:news, #:download, #content/blogcategory/4/7/) не передаются на сервер. Для загрузки пользователю соответственного ссылке контента мы вынуждены изначально загружать контент корневой страницы (http://site.ru/), потом определить AJAX якорь (#:news), и только теперь имеем возможность догрузить соответствующий якорю контент. Как видно из алгоритма работы, мы имеем первую излишнюю загрузку корневого контента, который по сути нам вообще не нужен. Визуально это сопровождается неприятным миганием страницы. Примеры работы указанной реализации увидеть вот здесь:
http://maxaman-soft.ru/#content/blogcategory/4/7/
http://www.pricelist.uz/ru/goods/catalog/#ru/goods/catalog/category/ofisnaya_tehnika/
Есть несколько вариантов решения данной проблемы. Один из них основан на временном сокрытии контента и последующим показом его только после дозагрузки соответствующего якорю контента. Данный подход все же имеет недостаток излишней загрузки контента. К сожалению, примеров такой реализации я не нашел.
Второй подход, который мне известен, это реализация первой страницы пустышки – и загрузка контента только после определения AJAX якоря. Примеры реализации можно увидать вот здесь:
http://www.datamash.us/#:chips:goto:gs12
http://fullajax.ru/examples/index.html#:[addscript]
Данный подход имеет недостаток индексации сайта поисковиками, они видят корневую страницу пустышку. Хотя здесь я оперирую общими алгоритмами, вполне возможно, что профессионалы в области поиска или оптимизации могут подробнее раскрыть тему индексации такого контента.
Кстати, здесь и кроется, на мое мнение, вторая проблема AJAX – все же он более подходит для реализации именно приложений, а контент и навигация в открытом доступе – это немного неправильно. В приложениях проблемы ссылок вообще не возникает (представить себе ссылку на свое открытое письмо в GMail-е я не могу, и такой надобности тем более), а вот разработчики обычных «контентных» сайтов часто слишком углубляются в красивости, не исследуя юзабилити своих проектов.
Вашему вниманию предлагается третий вариант решения проблемы «холостой загрузки контента». Ниже рассматриваемый подход называется fullajax direct link. Разработчиком этой технологии является Руслан Синицкий, который и выступает главным соавтором этого материала. Способ оригинален в своей реализации и призван существенно упростить или даже полностью решить все перечисленные выше проблемы.
Проблема решается написанием маленького javascript-а, который сможет сделать пару нехитрых операций. Суть алгоритма заключается в следующем.
При переходе пользователем по AJAX ссылке site.ru/#:news, изначально он попадает в корень нашего сайта site.ru. В первую очередь загружается наш маленький javascript, который определяет наличие реферера. Если реферер отсутсвует (пользователь ввел адрес в новое окно) или реферер с внешнего сайта (пользователь попал на наш сайт кликнув по ссылке на другом сайте), тогда мы сразу определяем AJAX якорь (#:news) и определяем соответственную ему страницу (к примеру, /content/news). Далее тут же делаем редирект на страницу /content/news, и, как только начали загружать данную страницу, в самом начале делаем обратный редирект на site.ru:#news. Мы попадаем опять в корень сайта, но уже имеем внутренний реферер. В этот момент включается серверный алгоритм, который при совпадении условий – запрос корня сайта и наличие внутреннего реферера – загружает вместо контента коренной страницы контент страницы, которая указана в реферере. Схема алгоритма представлена на рисунке ниже:
![](https://habrastorage.org/getpro/habr/olpictures/094/d46/902/094d4690222fc2a32fa7f37414a60346.gif)
Все редиректы делаются с помощью javascript-а, что позволяет при его отключении работать с сайтом как обычно.
Все было бы замечательно, если бы не некоторые особенности работы браузера InternetExplorer. Он напрочь отказывается сохранять реферер при редиректе с помощью JS! Но нашелся интересный выход из этой ситуации. Вашему вниманию представляется вариант решения данной проблемы (ведь сохранение реферера может пригодится и в других случаях). Оказывается, IE позволяет программно кликать по ссылкам! При этом браузер нормально редиректится и сохраняет реферер. В добавок, проблема с реферером есть и у Оперы. Правда при JS-редиректе реферер Опера сохраняет, но если после редиректа нажать обновить, Опера теряет реферер. Благо, Опера также позволяет программно кликать на ссылках.
И так привожу пример рабочего клиентского скрипта который реально используется на сайте разработчика данного подхода (http://fullajax.ru):
// Таблица или функция соответствия «AJAX якорей» реальным ссылкам ***** var links = { '/content/view/36' : 'main', '/content/blogcategory/27/74' : 'news', '/content/view/43/75' : 'technology', '/content/view/41/76' : 'portfolio', '/content/view/38/79' : 'connection', '/content/view/42/80' : 'license', '/content/view/45/83' : 'contacts', '/content/view/39/77' : 'developers', '/content/view/40/78' : 'links', '/content/view/65/84' : 'download' } //проверка запроса не коренной страницы if (location.pathname && location.pathname != '/') { var l; for (var i in links){ if (location.pathname.substring(0,i.length)==i) { l = links[i] + location.pathname.replace(i,''); break; } } l = '/'+(l?'#:'+l:''); //преобразование в AJAX ссылку с якорем // конец функции соответсвия **** var ua = navigator.userAgent.toLowerCase(); //реализация редиректа с сохранением реферера для ИЕ и Оперы if (ua.indexOf('opera') > -1 || ua.indexOf('msie') > -1) { //для ИЕ нужно чтобы ссылка была внутри документа if (ua.indexOf('msie') > -1) { document.write('<a href="'+l+'" id="redirect" style="display:none"> </a>') document.getElementById('redirect').click(); } else { //для Оперы можно просто создать обьект-ссылку и кликнуть по ней var a = document.createElement('a'); a.setAttribute('href', l); a.click(); } } else { //редирект для нормальных браузеров location.replace(l); } } else { //запрос коренной страницы // определяем реферер, и если он есть определяем внутрений он или нет var ref = document.referrer; if (!ref || ref.indexOf(location.hostname) == -1 || (ref.substring(ref.length-'fullajax.ru/'.length,ref.length)=='fullajax.ru/')){ var ind = location.href.indexOf('#:'); if (ind != -1){ //определяем AJAX якорь-ссылку var l = location.href.substring(ind+2); for (var i in links){ //определяем соответсвующую AJAX якорю реальную ссылку и редиректим на нее if (l.substring(0,links[i].length)==links[i]) location.replace(i+l.replace(links[i],'')); } } } }
Вот такие вот пироги :). К данному клиентскому скрипту прилагается серверный скрипт, который при наличии внутреннего реферера грузит вместо главной страницы, страницу которая указана в реферере. Привожу написанный на PHP рабочий пример реализации мамбота для CMS Joomla:
<?php /* * fullajax systembot * (c) 2008 boston & si-rus * В рамках проекта Fullajax для Joomla! * http://www.fullajax.ru | http://www.joostina.ru **/ defined( '_VALID_MOS' ) or die( 'Прямой вызов файла запрещён.' ); $_MAMBOTS->registerFunction( 'onStart', 'fullajaxStart' ); function fullajaxStart(){ global $mosConfig_live_site,$mosConfig_absolute_path,$mosConfig_sef; if(isset($_SERVER['HTTP_REFERER'])){ $_lo = strpos($_SERVER['HTTP_REFERER'],$mosConfig_live_site); if($_lo===false){ // реферер внешний - делаем всё как обычно null; }else{ //echo 'внутренний<br />'; $_ref = str_replace(array('http://','www.'),'',$_SERVER['HTTP_REFERER'] ); // реферер //echo '<br />'; $_url = str_replace(array('http://','www.'),'',$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'] ); // текущий урл - адрес //echo '<br />'; $_root = str_replace(array('http://','www.'),'',$mosConfig_live_site ).'/'; // урл корня сайта if($_url==$_root and $_url!=$_ref) { // запрос корня с внутренним реферером // грузим реферер require($mosConfig_absolute_path.'/templates/index/unsef.php'); }else{ null; } } } } ?>
Ну вот в принципе и все.
Данный алгоритм также имеет недостаток (таков закон сохранения энергии) – в итоге на 2 коннекта больше к серверу (2 редиректа), но это может быть мизерно малой долей по отношению к «холостой загрузки контента».
Преимущество рассмотренного подхода – сохраняется индексируемость главной страницы как у обычного сайта, нет загрузки ненужного контента («холостой запрос»), нет мигания страницы. Необходимость внедрения рассмотренного алгоритма зависит от конкретной ситуации. Возможно вам это пригодится. Пользуйтесь на здоровье!
Работу алгоритма в реальности можно увидеть на сайте http://fullajax.ru.
P.S. Автор материала: Руслан Синицкий (sirus, http://fullajax.ru), редактирование и соавторство – Александр Лозовюк (aleks_raiden, http://abrdev.com).