고민
- client 에서 front 서버로 front 서버에서 backend 서버로 get 요청을 보냈을 때에 에러가 몇가지 있었다.
- CORS, Credentials 의 문제로 서로 다른 주소 간 쿠키 전송의 어려움으로 쿠키가 전송되지 않았던 문제인데, 지금 서버사이드 렌더링을 준비하고서도 로그인에서 같은 문제가 발생했다.
front/pages.index.js
(...)
export const getServerSideProps = wrapper.getServerSideProps((store) => async () => {
store.dispatch({
type: LOAD_USER_REQUEST,
});
store.dispatch({
type: LOAD_POSTS_REQUEST,
});
store.dispatch(END);
await store.sagaTask.toPromise();
});
(...)
- 서버사이드 렌더링을 하기 위해 렌더링을 하기 전 서버로 요청을 보내는 getServerSideProps 코드를 잘 보면, 브라우저에서 실행되는 것이 아닌, 프론트서버에서 실행된다.
- 프론트 서버에서 백엔드 서버로 데이터랑 사용자 로그인되어 있는지 데이터를 GET 요청으로 응답을 받는다. 근데 프론트 서버랑 백엔드 서버가 서로 도메인이 다르다. 도메인이 다를 경우 쿠키전송이 되지 않는 문제를 해결하기 위해 Credentials: true 로 설정해주었다.
back/app.js
// [CORS error] 모든 브라우저에서 api 사용 허용
app.use(
cors({
origin: true,
credentials: true,
})
);
- 그치만 이미 true 로 설정을 해주었는데도 안되는 이유는 무엇일까 고민했습다.
그래서 받는 백엔드 쪽이 아닌 보내는 프론트에서 문제를 살펴보았다. 프론트에서 백엔드로 데이터 보낼 때 쿠키를 브라우저가 직접 담아줘서 Axios 요청을 보낼 대 헤더에 쿠키 설정을 별도로 하지 않아도 브라우저가 알아서 보내주었습니다.
그치만, 서버사이드 렌더링을 구현한 지금, 서버사이드 렌더링의 주체는 브라우저에서 프론트, 백엔드 서버로 보내는것이 아니라 프론트 서버에서 백엔드 서버로 보내는 것이었습니다.
왜냐면, 위에서 설명했듯이 서버사이드 렌더링을 실행하는 getStaticServersideProps 는 브라우저가 아닌 프론트 서버에서 실행되는 것이기 때문입니다.
결국, 쿠키를 보내지 않고 있었던 문제였습니다. 현재 브라우저가 아닌 서버에서 서버로 요청을 보내면 쿠키를 자동으로 보내주는 코드는 없기 때문이죠.
routes/user.js 의 login 라우트
router.get('/', async (req, res, next) => {
console.log(req.headers);
(...)
});
back 터미널
헤더에 쿠키 없는 거 확인
쿠키가 보내지 않았기 때문에 사용자가 로그인을 실제로 한 상태일지라도 백엔드는 로그인을 한 지 모르게 됩니다.
해결 노력
프론트 서버에서 백엔드 서버로 보내는 서버사이드렌더링 Axios 요청에 headers.default 로 cookie 넣기
(...)
export const getServerSideProps = wrapper.getServerSideProps((store) => async (context) => {
const cookie = context.req ? context.req.headers.cookie : '';
console.log(cookie);
axios.defaults.headers.Cookie = cookie;
store.dispatch({
type: LOAD_MY_INFO_REQUEST,
});
store.dispatch({
type: LOAD_POSTS_REQUEST,
});
store.dispatch(END);
await store.sagaTask.toPromise();
});
(...)
- const cookie = context.req ? context.req.headers.cookie : '';: 요청된 쿠키를 가져오기 위해 Next.js의 context 객체를 사용하고, 해당 요청에 쿠키가 없으면 빈 문자열로 설정됩니다.
- axios.defaults.headers.Cookie = '';: Axios의 헤더에 쿠키를 설정하기 전에 초기화합니다.
- if (context.req && cookie) { axios.defaults.headers.Cookie = cookie; }: 쿠키가 존재하고 요청이 서버 측에서 발생했으면, Axios의 헤더에 쿠키를 설정합니다.
- store.dispatch({ type: LOAD_MY_INFO_REQUEST });: Redux 스토어에게 내 정보를 로드하는 요청을 나타내는 LOAD_MY_INFO_REQUEST 타입의 액션을 디스패치합니다.
- store.dispatch({ type: LOAD_POSTS_REQUEST });: Redux 스토어에게 포스트 데이터를 로드하는 요청을 나타내는 LOAD_POSTS_REQUEST 타입의 액션을 디스패치합니다.
- store.dispatch(END);: Redux Saga에게 모든 비동기 작업이 완료되었음을 나타내는 END 액션을 디스패치합니다.
- await store.sagaTask.toPromise();: Redux Saga의 작업이 완료될 때까지 기다리고, 작업이 완료된 후에 프로미스를 반환합니다.
back 터미널
성과
서버사이드 렌더링 성공!
'Next.js' 카테고리의 다른 글
[NNN]_서버사이드렌더링 준비 (0) | 2024.02.26 |
---|---|
[NNN]_CSS 서버사이드 렌더링 준비 (0) | 2024.02.25 |
CSR 과 SSR (0) | 2024.02.24 |
[NNN]_트러블슈팅2_Infinite Scroll 멈추기 (0) | 2024.02.22 |
[NNN]_express.static 미들웨어, 사진 미리보기 (0) | 2024.02.21 |