Логування активності з використанням Web Beacon API

Beacon API — це заснований на JavaScript інтерфейс для:

відправлення невеликої кількості даних на сервер з браузера, без очікування відповіді. У цій статті ми розглянемо в яких випадках буде корисний Beacon API, чим він відрізняється від використання XMLHTTPRequest (Ajax) для тих же цілей і як його використовувати.

Для чого нам черговий API?

Beacon API використовується для відправки невеликих за обсягом даних на сервер без очікування відповіді. Остання частина твердження є найбільш цікавою. Beacon API розроблений спеціально для того, що б можна було відправити дані і забути про них. Не потрібно чекати відповідь, так як його і не буде.

Метафора з листівками, це такі картки які люди посилають/посилали один одному. Як правило, на них писали невеликий за обсягом текст (“Ти де? А я на морі лол.”, “Тут у мене шикарна погода, не те що у тебе в офісі”), кидали у скриньку і забували. Ніхто не чекав відповіді типу “Я вже виїхав за тобою”, “У мене в офісі чудово”.

Існує безліч випадків, коли підхід “відправив і забув” буде доречний.

Відстеження статистики та Аналітична інформація

Це перше, що приходить на розум. Такі великі рішення як Google Analytics можуть надавати хороший огляд на базові речі. Але якщо ми хочемо, що більш кастомізованих? Нам необхідно написати трохи коду для відстеження того, що відбувається на сторінці (як користувачі взаємодіють з компонентами, як далеко вони скролят, які сторінки були відображені до першого продажу), потім відправити ці дані на сервер, коли користувач залишає сторінку. Beacon ідеально підходить для рішення такої задачі, так як ми просто відправляємо дані, і нам непотрібний відповідь від сервера.

Дебаг і Логування

Інше застосування це логування інформації з JavaScript коду. Уявіть собі ситуацію, коли у вас велика програма з багатим UI/UX. Всі тести зелені, а на виявляли у своєму житті таку періодично спливає помилка, про яку ви знаєте, але не можете продебажить її через не хватки інформації. В даному випадку ви можете використовувати Beacon для діагностики.

Читайте також  Чому вести контекст на записі клієнта — чесно і вигідно

Насправді будь-яке завдання з логированиям може бути решешина з використанням Beacon. Це може бути створення точок збереження в іграх, збір інформації про іспользоаніі нового функціоналу, запис результатів тестування і так далі. Якщо це, те, що відбувається в браузері і ви хочете, що б сервер знав про це, Beacon це, те, що потрібно.

Хіба ми не робили цього раніше?

Я знаю про що ви думаєте. Ніщо з цього не ново? Ми спілкуємося з північчю допомогою XMLHTTPRequest вже більше 10 років. Нещодавно ми почали використовувати Fetch API, що за фактом робить те ж саме, просто з новим Promise інтерфейсом. Так навіщо нам ще один Beacon API?

Ключова особливість в тому, що нам не потрібен відповідь від сервера. Браузер може поставити в чергу запит та відправити дані не блокуючи виконання будь-якого коду. Так як в це впрягається браузер, для нас не важливо виконується ще код чи ні, браузер просто буде собі тихенько відправляти запити в тлі.

C Beacon API не потрібно чекати кращого моменту для CPU, мережі. Просто додати в чергу запит з допомогою beacon практично нічого не коштує.

Для того, що б зрозуміти чому це важливо, досить поглянути на те, як і де зазвичай використовуються подібна логіка. Наприклад для того, що б виміряти як довго користувач знаходиться на сторінці, нам необхідно відправити запит на сервер як можна ближче до кінця сесії.

Зазвичай це роблять на unload або beforeunload. Такий код може заблокувати виконання і якщо відбувається затримка вивантаження сторінок, то і завантаження наступної сторінки теж затримується. Це призводить до не краще UX.

Ви ж розумієте наскільки HTTP запити повільні? І останнє, що ви хочете, так це впихати HTTP запит між переходами.

Читайте також  Не можете зайти в AdWords? Що робити?

Пробуємо Beacon API

Базовий приклад використання дуже простий:

let result = navigator.sendBeacon(url, data);

result булевое значення. Якщо браузер додав запит в чергу — true, якщо немає false.

Використання navigator.sendBeacon()

navigator.sendBeacon приймає два параметри. Перший це URL на який буде посланий запит, другий це дані які потрібно відправити. Запит має вигляд HTTP POST.

data — цей параметр може приймати кілька форматів даних, всі ті, з якими працює Fetch API. Це може бути Blob, BufferSource, FormData або URLSearchParams і тд.

Мені подобається використовувати FormData для простих key-value даних, це не складний і простий у використанні клас.

// URL куди відправити дані
let url = '/api/my-endpoint';

// Створення нового FormData
let data = new FormData();
data.append('hello', 'world');

let result = navigator.sendBeacon(url, data);

if (result) { 
 console.log('Додано в чергу!');
} else {
console.log('Помилка');
}

Підтримка браузерами

Підтримка цього API цілком собі солідна. Єдиний браузер, який не підтримує, це Internet Explorer (не очікував я такого) і Opera Mini. Але Edge все працює. У більшості випадків підтримка є, але краще на всяк випадок перевірити:

if (navigator.sendBeacon) {
 // Beacon код
} else {
 // Використовувати XHR?
}

Приклад: логируем час проведений на сторінці

Для того, що б побачити все це на практиці, давайте створимо просту систему підрахунку часу яке знаходиться на сторінці. Коли сторінка завантажується ми дивимося на час і коли покидає її ми відправляємо запит з часу початку перегляду і поточне на сервер.

Так як нас цікавить тільки час, проведений на сторінці, а не нині, ми можемо використовувати performance.now() для отримання базового timestamp при завантаженні сторінки:

let startTime = performance.now();

Давайте обернем невеликий шматочок логіки в зручну у використанні функцію:

let logVisit = function() {
 // Test that we have support
 if (!navigator.sendBeacon) return true;

 // URL to send the data to, e.g.
 let url = '/api/log-visit';

 // Data to send
 let data = new FormData();
 data.append('start', startTime);
 data.append('end', performance.now());
 data.append('url', document.URL);

 // Let's go!
 navigator.sendBeacon(url, data);
};

І нарешті нам треба викликати цю функцію коли користувач залишає сторінку. Перша думка була використовувати unload, але Safari на Mac, схоже блокує запит з міркувань безпеки. З цього краще використовувати beforeunload:

window.addEventListener. ('beforeunload', logVisit);

Коли сторінка вивантажується (або перед цим), наша функція logVisit() буде викликана і якщо браузер підтримує Beacon API, відправить запит на сервер.

Читайте також  На які метрики спиратися, якщо на сайті користувачі виконують конверсії?

Пару моментів

Так як більша частина проблем, для вирішення яких буде використовуватися Beacon API, крутяться навколо відстеження активності, буде важливим відзначити соціальну і законну частину всієї цієї кухні.

GDPR

Просто пам’ятайте про нього.

DNT: DO NOT TRACK

На додаток, браузери мають опцію яка дозволяє користувачам визначити, що вони не хочуть, що б їх активність відстежувалася. Do Not Track відправляє HTTP хедер, який виглядає так:

DNT: 1

Якщо ви відстежуєте дані які можуть відображати користувача і в хедерах запитів є DNT: 1, то краще послухати користувача і не зберігати будь-які дані. Наприклад використовую PHP це можна перевірити наступним чином:

if (!empty($_SERVER['HTTP_DNT'])) { 
 // Не хочу, не треба
}

Висновок

Beacon API дійсно дуже зручний спосіб для відправки даних на сервер, особливо в контексті логування. Підтримка браузерами на досить хорошому рівні і дозволяє вам легко логировать будь-яку інформацію без будь-яких негативних последсвий для продуктивності і чуйності вашого UI. Non-blocking природа цих запитів грає в цьому дуже гарну роль, це горазно швидше альтернатив XHR і Fetch.

Степан Лютий

Обожнюю технології в сучасному світі. Хоча частенько і замислююся над тим, як далеко вони нас заведуть. Не те, щоб я прям і знаюся на ядрах, пікселях, коллайдерах і інших парсеках. Просто приходжу в захват від того, що може в творчому пориві вигадати людський розум.

You may also like...

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *