[Next.js] Redirect 기능 - resolvedUrl

hyejinJo·약 18시간 전
0

React

목록 보기
14/14
post-thumbnail

소플이라는 서비스에서 패널회원에 가입하는 루트를 작업하고 있었다.
패널회원에 가입하기 위해서는 로그인, 본인인증 두 가지 루트를 거쳐야 한다. 로그인이 안된 경우 로그인 페이지로 잘 리다이렉트 되는데, 본인인증의 경우 인증 후 패널 가입 페이지가 아닌 메인페이지(’/’)로 리다이렉트 되고 있었다.

처음 panel/intro 로 링크를 받으면 아래와 같은 분기가 태워진다.

  1. 로그인이 안되었을 경우 → 진입도 전에 바로 로그인 페이지로 리다이렉트
  2. 본인인증이 안되었을 경우 → 패널회원 가입하기 버튼 클릭 시 본인인증 페이지(/certification) 로 이동 후 다시 panel/join 으로 리다이렉트
  3. 본인인증이 되었을 경우 → 바로 본인인증이 완료된 표시와 함께 폼 등장

문제

하지만 2번 조건에서 본인인증 직후 바로 패널 가입 페이지(panel/join)으로 넘어가야하는데, 메인페이지(/) 로 리다이렉트되는 상황이었다.

그 이후 새로고침을 해야 4번 상황이 정상 동작했다..🤔

서버사이드 렌더링 환경이며, 코드는 다음과 같다.

...
const { session, url } = context.req;
let certificated = false;
let redirectUrl = '/';

if (url && !url.includes('_next')) {
  redirectUrl = url;
}

try {
    // 로그인 상태 체크
    const user = await checkAuth(session);
    if (user) {
      // 본인인증여부 체크하는 로직
			...
      if (checkCertification && !certificated) { // checkCertification - props 이며, boolean 값
        return {
          redirect: {
            permanent: false,
            source: redirectUrl,
            // 본인인증되지 않은 상태이면 인증페이지로 이동 > 인증 > 다시 이전 페이지로 redirect
            destination: `/certification?redirectUrl=${encodeURIComponent(redirectUrl)}`,
          },
        };
      }
    } else {
      store.dispatch(setUserMeta(null));
    }
  } catch (error: any) {
    if (redirect) {
      return {
        redirect: {
          permanent: false,
          source: redirectUrl,
          destination: `/login?redirectUrl=${encodeURIComponent(redirectUrl)}`,
        },
      };
    }
  }

본인인증이 완료되어 certificated 가 true 가 되면 redirect 되는 구조이다.

문제는 url && !url.includes('_next') 의 조건에서 false 가 나와 redirectUrl 이 루트 경로로 설정된 것 같았다.

const { session, url } = context.req;
let certificated = false;
let redirectUrl = '/';

console.log('----------------------------------------------------');
console.log(url)
if (url && !url.includes('_next')) {
  redirectUrl = url;
}

로그를 찍어보니, 다음과 같이 뜬다. (참고로 서버사이드렌더링 코드에서 콘솔을 찍으면 브라우저 콘솔창이 아닌 코드 터미널에서 확인이 가능하다.)

원래라면 아래와 같이 사용자 경로만 찍혀야 하는데, 앞에 _next 가 붙은 json 형태의 파일이름으로 내려오고 있는 것이었다. 그래서 url && !url.includes('_next') 부분에서 조건 이행이 안돼 메인홈으로 리다이렉트 되었던 것이다..


해결

resolvedUrl

그래서 찾아보니 context.req.url 이 아닌 context.resolvedUrl 을 사용하라는 내용이 있었다..!

context.resolvedUrl은 Next.js의 getServerSideProps 함수에서 제공하는 객체 중 하나로, 클라이언트가 요청한 경로와 쿼리 문자열(query string)을 포함한 값을 제공한다.

getServerSideProps는 브라우저에서 요청할 때 뿐만 아니라 내부적으로 클라이언트와 서버 간 데이터 요청을 처리할 때도 실행되며 이때 Next.js는 데이터 요청에 ‘_next/data’ 경로를 사용한다고 하는데, 이것이 문제의 원인이었다…

더 쉽게 말하면, 다음과 같다.

  • 브라우저가 페이지를 처음 로드하면 URL이 /panel/join과 같이 나타남
  • 하지만 이후 클라이언트 측에서 페이지를 이동하거나 데이터 페칭이 필요하면 내부적으로 /_next/data 경로로 요청이 발생함
속성설명예시
context.req.url브라우저 또는 내부 데이터 요청에서 전달된 원본 경로/_next/data/development/panel/join.json (데이터 요청 시)
context.resolvedUrl사용자 요청 URL (경로 + 쿼리 포함, _next/data 제외)/panel/join?ref=123

이전에 !url.includes('_next') 와 같은 조건을 둔 이유는 '_next' 부분이 문제가 되어 해당 부분을 제외한 url 을 추출하려 한건데, resolvedUrl 을 사용하면 이러한 과정도 모두 생략이 가능했다.

수정한 코드는 다음과 같다.

const { session } = context.req;
const { resolvedUrl } = context;

let certificated = false;
let redirectUrl = '/';

if (resolvedUrl) {
  redirectUrl = resolvedUrl;
}

결과:

resolvedUrl 을 적용한 결과, 본인인증이 안된 상태에서

인증 직후에 바로 패널회원가입 페이지로 리다이렉팅에 성공했다.

profile
Frontend Developer 💡

0개의 댓글

관련 채용 정보