본문 바로가기
  • 살짝 구운 김 유나
Web/JavaScript

페이지를 떠날 때 안정적으로 요청 보내기 - sendBeacon

by yunae 2023. 5. 21.

웹소켓을 활용한 실시간 게임을 제작했다. 
사용자가 페이지를 새로고침 하거나 브라우저를 닫았을 때, 서버 단에 사용자가 퇴장한다고 알리는 요청을 보내야 했다.

요청을 안정적으로 전송하기 위해서 Navigator에서 제공하는 sendBeacon을 사용하기로 했다.

 

일반적인 API 요청은 사용자가 브라우저를 닫을 때 요청이 전송되는 것을 보장하지 않는다.

sendBeacon으로 전송된 요청은 실제 에이전트에 의해 대기열에 존재하기 때문에 네트워크에 연결이 되어있기만 하면 데이터가 전송된다.

 

[참고 문서]

 

Navigator: sendBeacon() method - Web APIs | MDN

The navigator.sendBeacon() method asynchronously sends an HTTP POST request containing a small amount of data to a web server.

developer.mozilla.org

 

navigator.sendBeacon은 소량의 데이터가 포함된 HTTP POST 요청비동기적으로 전송한다.

 

사용방법

navigator.sendBeacon(url)
// or
navigator.sendBeacon(url, data)

- url : 데이터를 수신할 URL

- data : 서버에 보낼 데이터


리턴 값

전송을 위해 성공적으로 대기열에 넣은 경우 True를, 그렇지 않은 경우에는 False를 반환한다

 

이를 이용해서 요청을 전송해보자.

// apis.ts

// 참여자 퇴장
export const guestOutApi = async (payload: number) => {
  console.log(payload, 'pin!!!!!!!!!!');

  // 닉네임이 존재하는 사용자 일 경우에만 새로고침 할 수 있도록
  if (payload) {
    // 나가기
    const res = navigator.sendBeacon(`${BASE_URL}/game/${payload}/user/out`, data);
    console.log(res) // 성공적으로 대기열에 올라갔다면 true
  }
};

사용자의 퇴장을 알리는 컴포넌트를 하나 생성해서 작성하였다.

// Component.tsx

'use client';

import { useEffect } from 'react';
import { useRouter } from 'next/navigation';
// apis
import { guestOutApi, hostOutApi } from '@/apis/apis';
// redux
import { RootState } from '@/store/store';
import { useSelector } from 'react-redux';
import { guestOutAction } from '@/store/readyInfoSlice';
import { Guest } from '@/store/guestSlice';

export default function Component() {
  const guest: Guest = useSelector((state: RootState) => state.guest);
  const isHost: boolean = useSelector((state: RootState) => state.status.isHost);
  const pin: number = useSelector((state: RootState) => state.gameinfo.id);
  const router = useRouter();

  // 새로고침 또는 페이지를 이동할 때
  useEffect(() => {
    const handleBeforeUnload = (e: BeforeUnloadEvent) => {
      e.preventDefault();
      e.returnValue = '';

      // 호스트이면 방 폭파
      if (isHost) {
        hostOutApi(String(pin));
        router.push('/')
      }
      // 게스트 이면 퇴장 알리기
      else {
        if(guest.pin != 0) {
          // api 요청
          guestOutApi(guest?.pin);
          // 리스트에 반영
          guestOutAction(guest?.nickname);
          router.push('/')
        }
      }
    };

    window.addEventListener('beforeunload', handleBeforeUnload);
    return () => {
      window.removeEventListener('beforeunload', handleBeforeUnload);
    };
  }, [guest, pin]);

  return null;
}

실행결과를 보면 true 값이 잘 찍히는 것을 볼 수 있다.

 

 

 

 

3번째 플젝까지 끝! 아직 배울게 너무 많다고 느껴져서 취뽀 벽은 너무 높다@..! 그래도 꾸준히 하다보면 전문가가 되어있겠죠~̆̈

댓글