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

в 9:21, , рубрики: ajax, AngularJS, full-ajax, nginx

Большинство 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>

Автор: fls_welvet

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js