상세 컨텐츠

본문 제목

100% 모든 환경에 작동하는 페이지 이동 이벤트 포착 자바스크립트 코드 - JavaScript

본문

웹 애플리케이션을 만들다 보면 페이지 애널리틱스를 적용해야 하는 경우가 간혹 생깁니다.  저 같은 경우는 한 페이지에서 유저가 보던 동영상의 마지막 시점이 어디였는지를 유저가 다른 페이지나 사이트로 이동 전에 받아와서 다음에 같은 동영상을 볼 때 전 시점에서 이어 보기를 하기 위한 이유도 있었습니다.  다른 방법도 아주 많지만 기본적으로 유저가 다른 페이지로 이동 시에 데이터를 받아 저장을 해야 하는 방식을 썼었죠.  
 
윈도즈나 안드로이드 같은 경우는 브라우저 체제가 비슷하여 보편적으로 쓰이는 "onbeforeunload"라는 이벤트를 쓰는 방법으로 됩니다.  그렇지만 웹앱 호환성의 강적인 iOS라는 체제가 하나 있죠.  macOS 체제는 거의 윈도즈 브라우저 체제와 비슷하여 웹의 기본적인 것들이 호환이 되지만 iOS 에코시스템은 정말 다릅니다. 
 
이 부분으로 많은 골치를 앓았는데요 여기저기 흩어져 있는 문서와 저의 테스트로 어떤 환경에서도 가동이 되는 코드를 만들어 보았습니다. 
 

반응형

우선 이 글의 목표는 유저가 페이지 이동 시에 alert를 띄우는 것이 아니고 데이터를 송출하여 서버에 전달 및 저장하는 것이 목적입니다.  그러면 아래의 두 가지 문제가 주어지죠:
 

1.  모든 환경에 호환되는 페이지 이벤트
2.  그 이벤트에 호환되는 데이터 송출 방법

 
한 가지씩 알아보겠습니다.


1.  페이지 이벤트

onpageunload라는 이벤트는 iOS 에는 없어진 이벤트입니다.  애플 문서에는 다른 이벤트를 쓰라고 말하고 있죠.  pagehide 이벤트입니다.    이 이벤트도 매번 100% 확률로 구동이 되지는 않습니다.  제일 확실한 이벤트는 document.onvisibilitychange 이벤트 이죠. 이 이벤트는 모바일 디바이스에서 유저가 브라우저에 있다가 다른 앱 (사이트뿐만 아니라)으로 이동을 하여도 트리거가 됩니다.  
 
아래의 코드는 사용 예제입니다 (참고로 아래는 리액트 자바스크립트 코드예요, 그리고 window 가 아니고 document입니다):

// 페이지 이동 이벤트
useEffect(() => {
    const handlePageLeave = event => {
        if (document.visibilityState === "hidden") {
            updatePageStats();
        }
    };

    document.addEventListener(
        "visibilitychange", handlePageLeave);

    return () => {
        document.removeEventListener(
            "visibilitychange", handlePageLeave);

    };
});

위의 코드를 보시면 document.visibilityState라는 값이 hidden 일 때에 데이터 전송을 하는 함수를 실행하게 됩니다.  이 이벤트는 모든 환경에 호환합니다.  여기까지는 많이들 아실 거예요.  문서들이 많이 나와 있어서요.  그렇지만 데이터 송출에 대해서는 영문이나 한글 문서들이 많이 부실했습니다.
 

728x90

2.  데이터 송출

페이지 이동시에는 데이터 송출 방법이 아주 까다롭습니다.  제일 간단한 방법은 navigator.sendBeacon인데요, 이것이 좀 예민합니다.  보낼 수 있는 데이터 포맷이 한정적입니다.  간단한 텍스트 정도이죠.  그리고 Blob을 써서도 보내는데 이 부분도 100% 성공 확률이 없습니다.  sendBeacon 은 첫 패러미터가 api 서버 주소, 마지막 패러미터가 body입니다.  그 이상의 커스터마이징 (헤더를 넣는 정도) 은 Blob을 만들어 body 패러미터로 쓰는 수밖에 없죠.
 
저의 케이스는 데이터가 우선 json이고, api 서버가 도메인이 달라서 cors를 써야 하는 상황이었습니다.  cors에 json 데이터를 송출 할시에는 헤더 변경과 API 서버 cors 옵션 변경도 해주어야 하죠.  sendBeacon으로는 할 수 없는 케이스였습니다.  찾다 보니 fetch 코맨드에 keepalive: true라는 옵션을 넣으면 sendBeacon과 같은 커맨드가 되어 브라우저는 페이지 이동시 데이터 송출을 허용한다고 알게 되었습니다.
 
fetch 에는 여러 옵션이 있죠.  그래서 이 방법으로 아래 코드를 만들어 보았습니다.  (리액트 코드예요, 하지만 자바스크립트 기반이라 모두 이해하실 거예요)

const updatePageStats = useCallback(() => {
    // 송출할 데이터
    let analyticsData = JSON.stringify({
        userId: userId,
        movieId: movieId,
        recentEndPointSeconds: endPointSeconds
    });
    
    fetch("API 서버 주소", {
        keepalive: true,
        method: 'POST',
        mode: 'cors',
        headers: {
            "Content-Type": "application/json",
        },
        body: analyticsData
    });
}, [userId, movieId, endPointSeconds]);

fetch의 옵션을 이용하여 keepalive: true 만 넣어 준다면 페이지 이동시 100% 확률로 데이터 송출이 가능합니다.  하지만 각 API 서버의 세팅에 따라 fetch의 옵션을 바꾸어 주셔야 한다는 것 잊지 마세요.


즐거운 코딩되세요!


도움이 되셨거나 즐거우셨다면 아래의 ❤️공감버튼이나 구독버튼을 눌러 주세요~  감사합니다

 

 

728x90
반응형

관련글 더보기