Чистый код Короткие заметки веб-разработчика

Определяем геолокацию пользователя на сайте. Два примера решения

Вопрос частый, но от того не более простой. В этой статье расскажу о двух способах вычисления местоположения, о плюсах и минусах каждого и приведу примеры реализации на JavaScript.

Способ первый, через API

Он же самый часто приходящий в голову и очевидный. Основная проблема — точность и детализация. Обычно, хорошо если удалось хотя бы угадать город, а то и страну иной раз можно спутать с соседней. Это связно с тем, что в России очень много раз различные выделенные диапазоны IP адресов часто переходили между провайдерами. В результате все диапазоны смешались и понять какой IP относится к какому городу иногда достаточно трудно. Возможно, за пределами России это работает лучше.

Тем не менее, в сети полно сервисов, которые предоставляют API для получения геоданных по предоставленному IP или по IP запроса. Это удобно. Показывать примеры буду на примере API freegeoip.app

Это один из немногих БЕСПЛАТНЫХ сервисов. Есть ограничение в 15 000 запросов в час с 1 IP адреса. Язык подтягивается автоматически, исходя из IP запроса.

У них есть простая документация. Вкраце, можно сделать запрос на https://freegeoip.app/json/ и получить в JSON формате данные о положении пользователя. Замечу, если делать запрос не от имени пользователя, а с сервера, то нужно будет обращаться не напрямую к методу, а с указанием IP пользователя, которого мы пытаемся вычислить. Например: https://freegeoip.app/json/24.48.0.1

Я считаю, что такие штуки нужно делать через JavaScript, чтобы не замедлять редер страницы на стороне сервера. Особенно, когда речь идёт о синхронном коде PHP. Поэтому рекомендованная реализация выглядит так:

const getUserGeo = new Promise(function (resolve, reject) { //Замечу, что переменная одноразовая, это не функция
    const xhr = new XMLHttpRequest();
    xhr.open('GET', 'https://freegeoip.app/json/', true);
    xhr.send();

    xhr.onreadystatechange = function() {
        if (xhr.readyState !== 4) return;

        if (xhr.status !== 200) {
            reject(xhr.status + xhr.statusText);
        } else {
            resolve(JSON.parse(xhr.responseText));
        }

    }
});

getUserGeo
    .then(function (result) {
        console.log('User geolocation:');
        console.log(result);
    })
    .catch(function (error) {
        console.error('User geolocation error', error);
    });

Далее, уже можно делать что угодно с этими данными. Вычислить страну, город и примерные координаты таким образом получилось:

Способ второй, через JavaScript Geolocation API

Основная проблема этого метода — это ужасное окно, пугающее пользователя. Например:

Пример окна запроса разрешения

Если вас это не пугает — то этот способ использовать лучше и круче, чем первый.

В целом, ничего сложного в реализации нет. Всё, что нужно знать — это то, что API доступен из объекта navigator.geolocation. Поэтому можно сразу проверить наличие API в браузере, так как очень может быть, что браузер и не поддерживает нифига. Пример того, как проверить, доступен ли API:

if ("geolocation" in navigator) {
    console.log('Геолокация доступна');
} else {
    console.error('Геолокация не поддерживается на этом устройстве');
}

Далее, мы уже можем получить текущую позицию через функцию getCurrentPosition():

navigator.geolocation.getCurrentPosition(function (data) {
    console.log(data.coords);
});

В результате мы получим объект с координатами и точность данных:

Получить таким образом название города или, хотя бы, страны — не получится. Нужно будет дополнительно использовать геокодирование. Хотя, если вам нужны координаты — то это отличный способ. Особенно, когда речь идёт о мобильных устройствах.

Можно даже в прямом эфире получать данные о положении пользователя через функцию watchPosition(), что супер-интересно, но не в тему статья.

А вообще, рекомендую статью на MDN Web Docs о Geolocation API. Там и примеры есть, и подробное описание.

Чё использовать по-результату?

Зависит от того, что вам нужно. Если хотите быстро получить страну пользователя или город и точность не очень важна — используйте IP. Если хотите получить координаты или вам важнее точность и вы готовы сделать лишний запрос к геокореду, чтобы вычислить субъект по координатам — используйте Geolocation API.

В идеале, совмещать оба способа так, чтобы пользователю не нужно было ждать ответа от тысяч API и функционал подгружался максимально быстро.