Отправка запросов Ajax при закрытии страницы

Иногда нам нужно сделать некоторые отчеты, чтобы записать поведение пользователя, когда он покидает страницу. Или отправьте ajax-запрос сервера, чтобы уведомить сервер об уходе пользователя, например, об операции оформления заказа в живой комнате.
Эта статья разделена на две части, чтобы объяснить, как заполнить отчет о поведении при выходе.
1. Прослушивание событий
В браузере есть два события, которые можно использовать для прослушивания закрытия страницы, beforeunload и unload.beforeunload находится в документе, и ресурсы будут закрыты при вызове, когда документ все еще виден, и в случае этого закрытия все еще может быть отменен. Например, следующий способ написания позволит пользователям обновить или закрыть страницу, когда появится всплывающее окно, напоминающее пользователям о необходимости закрытия.
window.addEventListener("beforeunload", function (event) {
// Cancel the event as stated by the standard.
event.preventDefault();
// Chrome requires returnValue to be set.
event.returnValue = '';
});
unload is на странице уже выгружается, когда документ находится в состоянии:
- все ресурсы все еще существуют (изображения, iframe и т. д.);
- для пользователя не видны все ресурсы;
- взаимодействие с интерфейсом некорректно (window.open, alert, confirm и т.д.);
- ошибка не останавливает процесс выгрузки документа.
На основе двух приведенных выше методов вы можете реализовать событие, прослушивающее закрытие страницы, чтобы быть в безопасности, вы можете прослушивать оба события. Затем выполните обработку функции слушателя, чтобы событие закрытия вызывалось только один раз.
2. Отправка запроса
С вышеприведенным слушателем дело сделано только наполовину. Если мы отправим запросы ajax непосредственно в прослушивателе, мы обнаружим, что запрос прерывается браузером и не может быть отправлен. Когда страница выгружается, браузер не гарантирует, что асинхронный запрос будет успешно отправлен.
Есть несколько способов решить эту проблему.
Вариант 1. Отправить синхронный запрос ajax
var oAjax = new XMLHttpRequest();
oAjax.open('POST', url + '/user/register', false);//false is synchronization request
oAjax.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
oAjax.onreadystatechange = function() {
if (oAjax.readyState == 4 && oAjax.status == 200) {
var data = JSON.parse(oAjax.responseText);
} else {
console.log(oAjax);
}
};
oAjax.send('a=1&b=2');
Этот подход эффективен, но пользователю необходимо дождаться завершения запроса, прежде чем закрыть страницу. Это не очень хороший опыт для пользователя.
Вариант 2. Отправка асинхронных запросов и игнорирование прерывания ajax на стороне сервера
Хотя асинхронные запросы будут прерваны браузером, это возможно, если сервер может игнорировать прерывание и по-прежнему выполняться нормально. Например, в PHP есть функция ignore_user_abort для игнорирования прерывания, что требует модификации серверной части и, как правило, неосуществимо.
Вариант 3. Используйте navigator.sendBeacon для отправки асинхронных запросов
Ссылка MDN:
Как видно из введения, этот метод используется для отправки запросов, когда пользователь уходит. Идеально подходит для этого сценария. Способ его использования следующий.
navigator.sendBeacon(url [, data]);
Данные, которые sendBeacon поддерживает для отправки, могут быть данными типа ArrayBufferView, Blob, DOMString или FormData type.
Вот несколько способов отправки запросов с помощью sendBeacon, вы можете изменить формат заголовка и содержимого, поскольку обычно метод связи с сервер исправлен, если вы измените заголовок или содержимое, сервер не сможет его правильно распознать.
(1) Использование BLOB-объекта для отправки Преимущество использования BLOB-объекта для отправки заключается в том, что вы можете определить свой собственный формат содержимого и заголовок, например, следующим образом установить тип содержимого в application/x-www-form-urlencoded.
blob = new Blob([`room_id=123`], {type : 'application/x-www-form-urlencoded'});
navigator.sendBeacon("/cgi-bin/leave_room", blob);

(2) Используйте объект FormData, но тогда для типа содержимого будет установлено значение «multipart/form-data».
var fd = new FormData();
fd.append('room_id', 123);
navigator.sendBeacon("/cgi-bin/leave_room", fd);

(3) Данные также могут использовать объект URLSearchParams, а тип содержимого будет установлен на «text/plain;charset=UTF-8».
var params = new URLSearchParams({ room_id: 123 })
navigator.sendBeacon("/cgi-bin/leave_room", params);

Попробовав, мы можем обнаружить, что для отправки удобнее использовать блоб, а настройка контента более гибкая. Если отправленное сообщение не распознается фоном после захвата пакета, вы можете попробовать изменить строку или заголовок содержимого, чтобы найти подходящий способ отправки запроса.
Дополнительные материалы на PlainEnglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord .
Заинтересованы в масштабировании запуска вашего программного обеспечения? Ознакомьтесь с разделом Схема.