Sungtt

랭킹페이지 새로고침 시 내 순위가 안나오는 오류 본문

프로젝트/개인 프로젝트 [공책게임]

랭킹페이지 새로고침 시 내 순위가 안나오는 오류

sungtt 2022. 8. 19. 08:42

개요

랭킹페이지는 useEffect를 통해 서버에 데이터를 받아와 랭킹을 출력해준다.

자신의 순위를 보여주는 api는 스토어의 userId를 인자로 담아 그 값을 조회해서 출력해준다.
다른 페이지에서 렌더링 후 진입한다면 스토어에 값이 할당 되어있어 문제없이 출력되지만
랭킹 페이지에서 새로고침 시 userId 스토어값에 값이 undifined라서 api요청을 해서 랭킹이 안나오는 오류를 만났다.

 

해결 과정

먼저 req객체의 id변수를 사용하고자했다.

하지만 새로고침시에는 req객체에 아무값이 들어있지않았다.

이 원인을 생각해보았다.

 

원인은

서버에서는 api요청마다 jwt검증을 진행하고 jwt엔 유저의 id가 들어있다.

이를 req.decoded.userId 변수에 할당하여 여기저기 사용중이다.

하지만 늘 첫 검증시에는 토큰이 없다는 오류를 만나고있었다.

 

현재 새로고침 시 로그인 정보를 유지하는 방법의 전개다.(이 방법은 오류가 나고있는 방법)

1. 브라우저 새로 고침

2. DOM이 parsing될 때 로컬스토리지의 토큰을 획득

3. 토큰을 axios.post에 담아 login/localstorage에 api 요청

4. 모든 api요청은 서버 미들웨어를 통해 헤더에 들어있는 토큰을 검증 한다.(처음엔 헤더에 값이 없기때문에 오류)

5. 헤더토큰이 정상이라면 복호화된 값을 express request 변수에 추가

5-1. 헤더토큰이 없다면 바로 next()

6. login/localstorage api가 post로 들어온 토큰을 검증을 try한다

6-1. 토큰이 정상이면 토큰에 들어있는 id로 DB의 userInfo를 획득하고 토큰과 userInfo, id를 응답해준다.

6-2. 토큰이 비정상이면 위 값을 모두 undifined로 응답해준다.

7. 클라이언트는 login/localsotrage의 응답을 받아와  token값은 axios headers에 설정한다.

8. 응답받은 userInfo와 id는 스토어에 저장하여 프론트에 출력한다.

 

이때 브라우저 첫 렌더링때는 위 과정을 한번 거치기전에는

헤더에 아무값도 들어있지않기때문에 무조건 오류가 난다.

이때 토큰 검증을 못했으니 당연히 req변수들도 할당되어있지않는 상태다.

 

해결하려면 첫 api요청에 토큰검증에 바로 성공해야 랭킹페이지에서도 req변수를 참조하여 값을 조회할 수 있다.

두가지 방법을 생각했다.

 

첫번째

2번 과정에서 토큰을 획득하면서 axios headers를 설정한 뒤 api요청을 하는 것.

이러면 토큰의 유효성을 바로 검사할 수 있고,

토큰이 유효하다면 위 사이클을 한번 돌기전에도 서버에서 즉각적으로 정상적인 req변수 참조가 가능하다.

function loadUser() {
  try {
    let user: string | null = localStorage.getItem('token');
    if (!user) return;
    axios.defaults.headers.common['Authorization'] = user;
    store.dispatch(login_localstorage(user));
  } catch (e) {
    console.log(e);
  }
}
loadUser();

두번째

서버 미들웨어가 헤더에 토큰과 post에 들어온 토큰도 체크하는 것

이 방법도 작동은 하지만 코드도 보기싫어지고 기존보다 더 많은 비용이 든다.(물론 미미할것임..)

const jwtCheck = (req: Request, res: Response, next: NextFunction) => {
  let token: string | undefined = req.headers.authorization as string;
  console.log('바디에 들어있는 값');
  if (req.body.token) {
    try {
      req.decoded = checkToken(req.body.token.token);
      req.isToken = true;
      console.log('유효한 토큰');
      next();
    } catch (e) {
      console.log('만료된 토큰');
      req.isToken = false;
      next();
    }
  } else if (token) {
    try {
      req.decoded = checkToken(token);
      req.isToken = true;
      console.log('유효한 토큰');
      next();
    } catch (e) {
      console.log('만료된 토큰');
      req.isToken = false;
      next();
    }
  }

 

결론

첫번째 방법을 통해 해결하였다.

이제 랭킹페이지에서 새로고침하여도 userId값을 서버에서 바로 조회할 수 있게되었다.

요청 시 userId값을 넘겨줄 필요도 없게되었다.

물론 이는 다른 페이지의 userId를 인자로 담아 요청하는 모든 api에 해당된다.

Comments