С некоторой регулярностью по работе приходится сталкиваться с задачей определения регионального сайта или раздела, который нужно показать пользователю. Наиболее известным методом для ее решения является GeoIP (от www.maxmind.com): устаревшие на месяц базы распространяются бесплатно, за актуальные базы требуются ежемесячные отчисления.
Но давайте будем разбираться по порядку.
Решение этой задачи тривиально и заключается в двух-трех строках на любом серверном языке программирования. Все, что нам нужно знать, это 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 или что-нибудь похожее). В этом случае нам придется либо направлять все региональные запросы на бэкенд (сводя роль фронтенда к минимуму), либо писать дополнительный модуль (логику) для фронтенда, которая будет перенаправлять пользователя.
Давайте шаг за шагом разберем, как должно работать определение регионального сайта для пользователя.
redirect
или stay
), что этого пользователя нужно не перенаправлять, а выставить ему Cookie, позволяющую ему оставаться на новом сайте. Стоит сразу отметить, что по Referrer определить, можно ли пользователю оставаться или нет, получится не всегда (в частности, в Chrome есть баг, что он не передает Referrer при редиректах). Поэтому лучше иметь специальный URL, который отменяет перенаправление (это может быть полезно и в тестовых целях, и при выдачи прямых ссылок).Очень легкой (с серверной точки зрения) заменой описанной выше логики может стать ее клиентская реализация. В некоторых случаях мы можем обойтись вообще без дополнительной нагрузки на сервер. Как это сделать?
Рассмотренный выше алгоритм замечательно ложится на клиентскую логику (за исключением только определения страны по IP):
document.cookie
). Если сайт находится в списке разрешенных, более никаких действий не предпринимается.var language = navigator.systemLanguage || navigator.appVersion.replace(/.*\(.*;? ?([a-z]*).*\).*/,"$1")
document.write('local.js')
Если подвести итоги, в случае определенных сложностей при подключении логики региональных перенаправлений на сервере ее можно вынести в пользовательский браузер (в принципе, даже не затрагивая сам сервер), потеряв по дороге пользователей без JavaScript и немного тех, у кого отключены Cookie (это все меньше 1%), но полностью обезопасив себя от сбоев поискового индекса и дополнительной нагрузки на сервер.
Если перенаправления осуществляются между одним и тем же сайтом (или же ресурсы страницы расположены на CDN), то у пользователя не возникнет ситуации, когда загруженные ресурсы (до перенаправления с помощью JavaScript) оказались ненужными. Практически все CSS- / JavaScript-файлы для многоязычных сайтов делаются независимыми от используемого языка, что облегчает их подключение на всем сайте (или на всех сайтах) сразу. Пользователь просто загрузит часть ресурсов, часть (или всю) HTML-страницу, и будет перенаправлен на более подходящий ему адрес.
Если на сервере включено сжатие и размер Cookie сведен к минимуму, то ситуация для пользователя (отправка и получение 5–10 Кб для того, чтобы оказаться в нужном месте) будет совершенно рядовой. Очень часто общий размер пересылаемых данных между браузером и сервером перед получением самих HTML-данных как раз и составляет те самые 5–10 Кб (имеются в виду HTTP-заголовки).
Не стоит считать описанный метод панацеей, но он может помочь в определенных ситуациях (в том числе, для уточнения региона пользователя по его языку).