Как можно отправить запрос на сервер, когда пользователь закрывает вкладку?

Как отправить запрос на сервер при закрытии вкладки, чтобы указать, что пользователь не в сети (параметр online = 0), используя стек технологий React, PHP и MySQL, если у меня нет доступа к серверу? Я работаю с обычным хостингом. 

У меня уже есть следующий код, который запускет нужное действие:

<pre><code class="javascript">useEffect(() =&gt; {
    
        const handleBeforeUnload = (event) =&gt; {
                QDB.edit(manager.id, { online: 0, logout_date: D_TimeNow(), navigator: navigator.userAgent }, 'users');
        };
    
        window.addEventListener('beforeunload', handleBeforeUnload);
        return () =&gt; { window.removeEventListener('beforeunload', handleBeforeUnload); };

    }, []);</code></pre>

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

<b>Как можно игнорировать перезагрузку страницы?</b>

Я слышал, что можно использовать sessionStorage для решения данной задачи, но у меня это не сработало. Вот что я пробовал:

<pre><code class="javascript">const sessionSecondLoad = sessionStorage.getItem('sessionSecondLoad');
if (!sessionSecondLoad) sessionStorage.setItem('sessionSecondLoad', 'true');
// Функция размонтирования компонента
const handleBeforeUnload = (event) =&gt; {
    sessionStorage.getItem('sessionSecondLoad'); // здесь я получаю true, но не могу определить, что это закрытие вкладки, а не перезагрузка
}</code></pre>
  • 23 сентября 2024 г. 21:23
Ответы на вопрос 2
Чтобы различить закрытие вкладки и перезагрузку страницы в браузере, действительно можно использовать `sessionStorage`, но основная проблема заключается в том, что обработчик события `beforeunload` вызывается как при закрытии вкладки, так и при перезагрузке страницы. В вашем случае можно использовать комбинацию `sessionStorage` и `visibilitychange` события для отслеживания состояния вкладки.

Вот пример, который может помочь вам реализовать данную функциональность:

```javascript
import React, { useEffect } from 'react';

const MyComponent = ({ manager }) => {
    
    useEffect(() => {
        const handleVisibilityChange = () => {
            if (document.visibilityState === 'hidden') {
                // Вкладка скрыта. Сохраняем состояние в sessionStorage.
                sessionStorage.setItem('tabHidden', 'true');
            }
        };
        
        const handleBeforeUnload = (event) => {
            const tabHidden = sessionStorage.getItem('tabHidden');
            if (tabHidden === 'true') {
                // Отправляем запрос на сервер о том, что пользователь не в сети
                QDB.edit(manager.id, { online: 0, logout_date: D_TimeNow(), navigator: navigator.userAgent }, 'users');
                sessionStorage.removeItem('tabHidden'); // Очищаем состояние
            }
        };
        
        document.addEventListener('visibilitychange', handleVisibilityChange);
        window.addEventListener('beforeunload', handleBeforeUnload);

        return () => {
            document.removeEventListener('visibilitychange', handleVisibilityChange);
            window.removeEventListener('beforeunload', handleBeforeUnload);
        };
    }, [manager.id]);

    return <div>Your Component Content</div>;
};

export default MyComponent;
```

### Как это работает:

1. **Обработчик `visibilitychange`:**
   - Когда состояние видимости вкладки меняется (например, вкладка скрыта или восстановлена), мы проверяем, когда вкладка была скрыта. Если она скрыта, записываем в `sessionStorage` значение `tabHidden`.

2. **Обработчик `beforeunload`:**
   - При вызове `beforeunload` проверяем, было ли значение `tabHidden` установлено. Если оно установлено, это значит, что пользователь закрыл вкладку, и мы можем безопасно отправить запрос на сервер.

3. **Очищение состояния:**
   - После отправки запроса мы очищаем значение в `sessionStorage`, чтобы не повторять запрос, если пользователь перезагрузит страницу.

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

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

useEffect(() => {
  sessionStorage.setItem('isReloading', 'true');

  const handleBeforeUnload = (event) => {
    const isReloading = sessionStorage.getItem('isReloading');
    if (isReloading === 'false') {
      QDB.edit(manager.id, { online: 0, logout_date: D_TimeNow(), navigator: navigator.userAgent }, 'users');
    }
  };

  const handleUnload = () => {
    sessionStorage.setItem('isReloading', 'false');
  };

  window.addEventListener('beforeunload', handleBeforeUnload);
  window.addEventListener('unload', handleUnload);

  return () => {
    window.removeEventListener('beforeunload', handleBeforeUnload);
    window.removeEventListener('unload', handleUnload);
  };
}, []);
Похожие вопросы