Как сохранить информацию о сеансе пользователя, когда пользователь закрывает веб-сайт

Я пытаюсь создать функциональность сеанса воспроизведения пользователя для веб-сайта и использую для этого библиотеку rrweb .

Что делает эта библиотека, так это при записи: она фиксирует все события на веб-странице, и я могу сохранить эти события, сохранив их в файле, и когда я захочу воспроизвести сеанс, я просто передам их функции воспроизведения, и это функция обрабатывает воспроизведение сеанса.

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

      rrweb.record({
    emit(event) {
        const sessions = JSON.parse(sessionStorage.getItem('sessions')) || [];
        sessions.push(event);
        sessionStorage.setItem('sessions', JSON.stringify(sessions));
    },
});

Однако для производства вместо сохранения этого массива в моемsessionStorageа затем обновлять его каждый раз, когда генерируется новое событие, я хотел бы сохранить его в своей базе данных, и я хочу вызвать функцию, которая сохранит его в моей базе данных один раз, когда пользователь или когда пользователь решит закрыть веб-сайт ( например, нажав кнопкуXкнопка).

Первая часть - когда пользовательlogs out- довольно прямолинейно, я просто добавлюeventListenerнаlogoutКнопка, вторая часть — когда пользователь решает закрыть веб-сайт — вызывает у меня некоторую головную боль.

Я знаю, что естьbeforeUnloadсобытие, однако после быстрого поиска мне стало ясно, что оно ненадежно, поэтому, по сути, я ищу надежный способ определить, когда пользователь закрыл мой веб-сайт, чтобы я мог запуститьasync functionэто спасло быarrayв мою базу данных.

3 ответа

Вот мои мысли о том, что вы можете сделать, чтобы уменьшить ненадежность события:

  1. Когда страница первоначально загружается, получите и сохраните текущее количество записей в вашем массиве. Предполагая, что мы говорим об одной странице, которую вы хотите воспроизвести, это количество можно сохранить как переменную JavaScript. А еще лучше было бы получить счетчик из серверной таблицы на случай, если по какой-то причине не все записанные события были успешно сохранены при последнем закрытии страницы.
  2. Организуйте функциюcheckEventsназываться каждыйNсекунд (вы должны решить, как часто вы хотите вызывать эту функцию) с помощью окнаметод. Эта функция будет просматривать текущее количество событий (переменная), и если оно больше текущего значения, то метод Navigator можно использовать для POST-запроса на сервер, передавая все события, которые были добавлены с момента последнего вызова (т. е.JSON.stringify(sessions.slice(eventCount, newCount))и когда запрос завершится, назначьтеeventCount = newCountесли это >eventCount. Обратите внимание, что во время выполнения асинхронного запроса могут быть сгенерированы новые события, поэтому мы обновляем счетчик событий с помощьюnewCountа не текущий размерsessionsмножество.
  3. Вам нужно будет выполнить последний запрос, когда страница будет выгружена. Поскольку мы знаем, чтоbeforeunloadиunloadсобытия ненадежны, то мы используемvisibiltychangedсобытие (если поддерживается браузером), и когда новое состояние видимости «скрыто», мы обновляем сервер. В документации обсуждаются те действия пользователя, которые приводят к запуску этого события (а не только при закрытии страницы). Однако если браузер не поддерживает это событие, тоpagehideсобытие необходимо будет использовать.

Это не обсуждается в документации кNavigator.sendBeaconметод, может ли быть несколько одновременных запросов. Если предположить, что это возможно (это асинхронный вызов), существует небольшая вероятность того, что пользователь может решить уйти со страницы или закрыть ее, покаsendBeaconзапрос в настоящее время находится в обработке из-заsetIntervalвызов. Тогда URL-адрес сервера, на который вы отправляете этот запрос, вероятно, должен заблокировать таблицу во время вставки, чтобы любой последующий POST к этому URL-адресу был заблокирован до тех пор, пока не завершится предыдущий. Другое решение, которое я бы предложил, если ваша таблица использует какой-то порядковый номер в качестве первичного ключа, это также передать на сервер индекс начального массива первого передаваемого события, и сервер будет использовать его для явной установки порядкового номера для каждого событие вставлено. Тогда параллельные обновления можно было бы выполнять без блокировки всей таблицы.

Введение

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

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

выйти

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

Итак, вам нужно:

  • уметь загружать массив из базы данных, передавать его в пользовательский интерфейс и делать его работоспособным
  • иметь возможность изменять массив каждый раз, когда такая модификация необходима
  • иметь возможность отправить массив на ваш сервер, который будет хранить его

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

Вам нужна функция, которая будет запускаться при каждом изменении, и еще одна, которая будет запускаться при каждой отправке. И вам, вероятно, потребуется сделать второй запрос AJAX и запускать этот запрос AJAX при нажатии кнопки выхода из системы и выходить из системы только после завершения сохранения.

Вы сказали, что это ненадежно. Итак, посмотрим, как проявляется эта ненадежность: Надежность onbeforeunload

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

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

периодические сохранения

Вы можете запустить, который периодически будет вызывать вашу функцию отправки (пока есть какие-то изменения для сохранения), и, если это выполняется каждые 5 минут, то максимальная потеря данных составит 5 минут, что происходит только в том случае, если в браузере/ОС/компе есть разбился, так что это будет очень редкая ситуация с минимальным ущербом.

сохранение каждого изменения

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

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

Вебсокет

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

Заключение

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

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

          window.onunload=()=>{
      //function to save the event in the database
}

Пусть это поможет вам.

Другие вопросы по тегам