Статьи Архив статей

Автор: Мациевский Николай aka sunnybear
Опубликована: 17 февраля 2009

Клиентский геотаргентинг

С некоторой регулярностью по работе приходится сталкиваться с задачей определения регионального сайта или раздела, который нужно показать пользователю. Наиболее известным методом для ее решения является GeoIP (от www.maxmind.com): устаревшие на месяц базы распространяются бесплатно, за актуальные базы требуются ежемесячные отчисления.

Но давайте будем разбираться по порядку.

Определяем географическое положение по IP

Решение этой задачи тривиально и заключается в двух-трех строках на любом серверном языке программирования. Все, что нам нужно знать, это IP-адрес пользователя. По нему нам может быть выдана его страна, город или какая-либо другая информация. Естественно, что на точный почтовый адрес рассчитывать не приходится, но для отображения для пользователя релевантного содержания этого вполне достаточно.

Выглядит это примерно следующим образом (пример конфигурации с модулем для Apache):

GeoIPEnable On
GeoIPDBFile /path/to/GeoIP.dat

# Перенаправляем одну страну
RewriteEngine on
RewriteCond %{ENV:GEOIP_COUNTRY_CODE} ^CA$
RewriteRule ^(.*)$ http://www.canada.com$1 [L]

# Перенаправляем несколько стран
RewriteEngine on
RewriteCond %{ENV:GEOIP_COUNTRY_CODE} ^(CA|US|MX)$
RewriteRule ^(.*)$ http://www.northamerica.com$1 [L]

Вроде пока все просто.

Подвох первый: соответствие стран регионам

Представим типичную ситуацию: у вас 2, 3 или 5 региональных сайтов / разделов на сайте. А стран (или городов) несколько сотен (если не тысяч). Как тут быть?

Естественным решением будет создать хэш из стран-городов, которые определяются по GeoIP (список стран легко найти, с городами чуть сложнее, но для России вроде выкладывали уже базу). Если у нас есть, например, русский и английский сайты, то мы можем определить для всех стран СНГ русский сайт, а для всех остальных назначать английский по умолчанию.

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

Подвох второй: запоминаем выбор пользователя

Давайте представим такую ситуацию: пользователь находится в России, но комфортнее ему итать материал на английском (турист, бизнесмен или просто GeoIP неточно определило его метонахождение). Для двух сайто ситуация может быть нечастой, но в случае десятка регионов такие ошибки могут происходить регулярно.

Как быть? Мы можем предоставить пользователю дополнительно самому выбрать свой регион (просто выпадающее меню, например). Чтобы пользователю не пришлось выбирать другой сайт постоянно (при каждом заходе на сайт, когда его будет перенаправлять на ненужный ему регион), мы можем запоминать его выбор в Cookie. Это просто.

Подвох третий: серверная конфигурация

Хотя база GeoIP работает весьма шустро, но при большом наплыве пользователей на сайт она может существенно нагрузить сервер. Если добавить к этому дополнительные запросы при перенаправлении (т.е. пользователь сначала запрашивает один сайт, срабатывает серверная логика — пользователь запрашивает другую страницу или сайт), не считая даже издержек на проверку и установление Cookie, то дополнительная региональная нагрузка может привести к отказу сервера.

Дополнительные сложности возникают, если используется связка «кэширующий фронтенд — вычисляющий бэкенд» (nginx-Apache, squid-Apache или что-нибудь похожее). В этом случае нам придется либо направлять все региональные запросы на бэкенд (сводя роль фронтенда к минимуму), либо писать дополнительный модуль (логику) для фронтенда, которая будет перенаправлять пользователя.

Логика для региональных перенаправлений

Давайте шаг за шагом разберем, как должно работать определение регионального сайта для пользователя.

  1. Во-первых, нам нужно проверить Cookie пользователя и узнать, можно ли ему находится на текущем сайте. Если можно, то дальнейшую логику и не запускаем.
  2. Если Cookie у пользователя не установлена, то нам нужно узнать его региональный сайт (по стране, полученный из GeoIP с помощью IP адреса пользователя, и хэша соответствия стран и регионов) и перенаправить на нужный сайт.
  3. При перенаправлении нам нужно обязательно в целевом URL поставить какую-либо метку (например, redirect или stay), что этого пользователя нужно не перенаправлять, а выставить ему Cookie, позволяющую ему оставаться на новом сайте. Стоит сразу отметить, что по Referrer определить, можно ли пользователю оставаться или нет, получится не всегда (в частности, в Chrome есть баг, что он не передает Referrer при редиректах). Поэтому лучше иметь специальный URL, который отменяет перенаправление (это может быть полезно и в тестовых целях, и при выдачи прямых ссылок).
  4. Нужно убедиться, что описанная логика не будет работать для поисковых роботов. Это очень важно для индексации. В частности, поисковые роботы нельзя перенаправлять, и нельзя для них светить эти самые специальные URL, иначе это неизбежно ударит по весам сайтов и таким образом по поисковой выдаче.
  5. Дополнительно можно позаботиться, чтобы Cookie выставлялись, если пользователь переходит с одного регионального сайта на другой (чтобы избежать ненужных перенаправлений) — это уже можно будет определить по Referrer.

Клиентский геотаргетинг

Очень легкой (с серверной точки зрения) заменой описанной выше логики может стать ее клиентская реализация. В некоторых случаях мы можем обойтись вообще без дополнительной нагрузки на сервер. Как это сделать?

Рассмотренный выше алгоритм замечательно ложится на клиентскую логику (за исключением только определения страны по IP):

  1. У пользователя, приходящего на сайт, проверяется через JavaScript Cookie (document.cookie). Если сайт находится в списке разрешенных, более никаких действий не предпринимается.
  2. Если текущий сайт не находится в списке разрешенных, то нам нужно каким-либо образом установить нужный вариант:
    • Либо через пользовательский язык системы, например так:
      var language = navigator.systemLanguage ||
          navigator.appVersion.replace(/.*\(.*;? ?([a-z]*).*\).*/,"$1")
    • Либо через запрос к серверу, например:
      document.write('local.js')
    Хочется сразу обратить внимание, что искомый код должен располагаться в самом верху страницы, чтобы заблокировать ее загрузку и перенаправить пользователя до появления ненужного материала на экране браузера.
  3. Непосредственно перед перенаправлением (или сразу же после) нужно выставить Cookie, что пользователю разрешено быть на перенаправленном сайте. В случае, если у нас есть URL, который не редиректит, то можно перенаправлять на него и выставлять Cookie уже при приеме пользователя на нужной странице или сайте. Стоит также отметить, что в любом случае нужна будет серверная поддержка решения на уровне дублирования логики выставления Cookie для выбранного сайта. Поэтому эту логику можно целиком оставить на совести сервера.
  4. Для случая людей с отключенными Cookie дополнительно можно проверять, не переходит ли пользователь с одной страницы домена на другую или с одного сайта на другой. И также ничего не делать: ведь пользователь сам пошел в определенный региональный раздел.
  5. И в качестве приятного бонуса: пользователя стоит направлять на региональный URL, в точности соответствующий текущему (т.е. содержащий ту же самую информацию, но более подходящую пользователю по региональному признаку). Ведь так приятно вместо: страницы на английском увидеть ее же, но на русском.
  6. Поисковые роботы идут лесом, ибо логику работы JavaScript не анализируют. Нас интересуют только пользователи.

Заключение

Если подвести итоги, в случае определенных сложностей при подключении логики региональных перенаправлений на сервере ее можно вынести в пользовательский браузер (в принципе, даже не затрагивая сам сервер), потеряв по дороге пользователей без JavaScript и немного тех, у кого отключены Cookie (это все меньше 1%), но полностью обезопасив себя от сбоев поискового индекса и дополнительной нагрузки на сервер.

Если перенаправления осуществляются между одним и тем же сайтом (или же ресурсы страницы расположены на CDN), то у пользователя не возникнет ситуации, когда загруженные ресурсы (до перенаправления с помощью JavaScript) оказались ненужными. Практически все CSS- / JavaScript-файлы для многоязычных сайтов делаются независимыми от используемого языка, что облегчает их подключение на всем сайте (или на всех сайтах) сразу. Пользователь просто загрузит часть ресурсов, часть (или всю) HTML-страницу, и будет перенаправлен на более подходящий ему адрес.

Если на сервере включено сжатие и размер Cookie сведен к минимуму, то ситуация для пользователя (отправка и получение 5–10 Кб для того, чтобы оказаться в нужном месте) будет совершенно рядовой. Очень часто общий размер пересылаемых данных между браузером и сервером перед получением самих HTML-данных как раз и составляет те самые 5–10 Кб (имеются в виду HTTP-заголовки).

Не стоит считать описанный метод панацеей, но он может помочь в определенных ситуациях (в том числе, для уточнения региона пользователя по его языку).

Читать дальше

Все комментарии (habrahabr.ru)