소플이라는 서비스에서 패널회원에 가입하는 루트를 작업하고 있었다.
패널회원에 가입하기 위해서는 로그인, 본인인증 두 가지 루트를 거쳐야 한다. 로그인이 안된 경우 로그인 페이지로 잘 리다이렉트 되는데, 본인인증의 경우 인증 후 패널 가입 페이지가 아닌 메인페이지(’/’)로 리다이렉트 되고 있었다.
처음 panel/intro 로 링크를 받으면 아래와 같은 분기가 태워진다.
하지만 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’ 경로를 사용한다고 하는데, 이것이 문제의 원인이었다…
더 쉽게 말하면, 다음과 같다.
/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
을 적용한 결과, 본인인증이 안된 상태에서
인증 직후에 바로 패널회원가입 페이지로 리다이렉팅에 성공했다.