Pull to refresh

HTML5/AngularJS/Nginx приложение с правильным с google-индексированием

Reading time 3 min
Views 38K
Original author: Alexey Kutuzov
Большинство web-приложений и web-фреймворков используют архитектуру, не позволяющую разделить ui и backend разработку. Тем самым нет возможности разделить команду на узкоспециализированных frontend и backend разработчиков. Вне зависимости от предпочтений разработчика ему приходится иметь понимание как о слое представления, так и о слое логики. Если ui-разработчик знает только о том, как запустить сервер, и о модели данных — это огромная удача. В плохих случаях ui-разработчику необходимо провести полную сборку проекта чтобы увидеть изменения строчки в javascript файле, или знать о языке jsp файлов чтобы поменять стиль элемента. Формирование и передача на сервер обработанных html файлов так-же пагубно влияет на производительность сервера и сети.

non-ajax



В наше время современных браузеров с поддержкой HTML5, WebSocket и Full Ajax приложений больше нет необходимости забивать backend-сервера чем-то отличным от бизнес логики. Вся ui-разработка может вестись на nginx сервере с заглушками api сервисов. А фреймворки для авто-генерации документации помогут и ui, и backend разработчикам снизить затраты на коммуникацию. Передача одних лишь json данных также существенно снизит нагрузку на сервера. Ведь сжатый javascript код ui-клиента можно держать в кеше приложения.

Но если современные бразуеры с легкостью справятся с возросшей ответственностью, то поисковым системам нужна помощь.

Для правильной индексации приложения на angularjs нам понадобятся следующие вещи:

  • sitemap.xml
  • html5Mode
  • nginx
  • old fashion backend server


image

HTML5 mode

Html5 mode превращает angularjs routes из вида example.com/#!/home в вид example.com/home (все href ссылки должны также указывать на url без hashbang). Чтобы включить html5mode нужно выполнить:

$locationProvider.html5Mode(true);
$locationProvider.hashPrefix('!');

я оставляю ! для совместимости с браузерами, не поддерживающими javascript

Теперь необходимо чтобы наш nginx сервер отправлял запросы с example.com/home на главный index.html файл приложения. Для этого укажем в конфиге следующую директиву:

location / {
        expires -1;
        add_header Pragma "no-cache";
        add_header Cache-Control "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";
        root /var/web;
        try_files $uri $uri/ /index.html =404;
    }


Строка try_files $uri $uri/ /index.html =404; означает что теперь все несуществующие url будут переадресованы на index.html файл, сохранив при этом url в адресной строке браузера.
Это решение уже является рабочим (а также совместимым с старым hashbang форматом ссылок) и если ваше приложение не должно индексироваться поисковыми системами то можно закончить.

SEO

Теперь поможем поисковику обработать наше приложение правильно. Для этого мы подготовим подсказки для бота и сгенерируем snapshot страниц. Для начала расскажем ему о том, какие страницы нужно индексировать с помощью sitemap.xml файла. Простейший вариант файла состоит из ссылок на страницы и даты их последнего обновления (более подробный формат есть на сайте www.sitemaps.org):

<urlset xmlns='http://www.sitemaps.org/schemas/sitemap/0.9'>
  <url>
    <loc>http://senior-java-developer.com/java/basics</loc>
    <lastmod>2013-07-12</lastmod>
  </url>
  <url>
    <loc>http://senior-java-developer.com/</loc>
    <lastmod>2013-07-12</lastmod>
  </url>
</urlset>


Отлично, поисковик будет запрашивать ссылки нашего сайта и получать контент index.html т.к. никакой обработки javascript в поисковые боты не встроено. Расскажем боту что за технической страницей `index.html` спрятан реальный контент. Для этого в заголовок страницы добавим:

<meta name="fragment" content="!" />


Это даст боту возможность сделать следующий шаг. Увидев fragmet=! бот запросит страницу еще раз, но добавит в конец url параметр ?_escaped_fragment_=. Подскажем nginx что запросы с данным параметром нужно отправлять в другое место:

if ($args ~ "_escaped_fragment_=(.*)") {
	rewrite ^ /snapshot${uri};
}		
location /snapshot {
    proxy_pass http://api;
    proxy_connect_timeout  60s;
}


Вот и все, теперь все запросы от бота будут отправлены к api backend серверу.

Real url Bot url Backend url
example.com example.com/?_escaped_fragment_= localhost:8080/snapshot/
example.com/home example.com/home?_escaped_fragment_= localhost:8080/snapshot/home


Для формирования снапшота я использую thymeleaf. Т.к. и thymeleaf, и angularjs используют html5 атрибуты можно использовать единый файл шаблона, однако я предпочитаю не смешивать их.

Строчка из html view выглядела бы примерно так:

<div ng-bind="text" th:text="${text}"></div>
Tags:
Hubs:
+29
Comments 7
Comments Comments 7

Articles