ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Nextjs에서 Nestjs로 accessToken header로 요청할때 오류
    Next.js 2022. 12. 26. 18:46
    728x90

    Unhandled Runtime Error

    AxiosError: Network Error

     

    has been blocked by CORS policy: Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response

     

    accessToken을 헤더로 전송할때 또 오류가 났다.

    //NextJs
    
    export const AuthApiClient = axios.create({
        baseURL: "http://localhost:3001",
        withCredentials: true,
        headers: {
            'Content-type': 'application/json',
            'Authorization': 'Bearer '+getFromStorage('accessToken')
        },
        transformRequest:[
            (data) => {
                return JSON.stringify(data);
            },
        ],
        transformResponse: [
            (data) => {
                return JSON.parse(data);
            },
        ],
    })
    Nextjs에서 header에 토큰 담아서 보낼때 Authorization으로 보내는데 Nestjs에서 그걸 허용 안해줘서 CROS 발생
    //NestJs
    async function bootstrap() {
      const app = await NestFactory.create(AppModule);
      const options = {
        origin: true,
        methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
        preflightContinue: false,
        credentials: true,
        allowedHeaders: 'Content-Type, Accept, Authorization',
      };
      app.enableCors(options);
      app.use(logger3);
      app.useGlobalPipes(new ValidationPipe({
        transform : true,
      }));
      //cookieParser
      app.use(cookieParser());
      await app.listen(3001);
    }
    
    
    allowedHeaders: 'Content-Type, Accept, Authorization',
    - 이부분에 Authorization 추가 허용

     


     

    체크포인트) Nextjs에서 헤더에 AccessToken 담아서 보낼때 localStorage에 꺼내서 쓰는데 Nextjs에서 localStorage에 가져와서 쓸려면 아래와 같이 해야함

    export const getFromStorage = (key:string) => {
        if (typeof window !== 'undefined') {
            return window.localStorage.getItem(key);
        }
    }

    왜냐하면 Next는 무조건 브라우저에서만 실행되는게 아니기 때문입니다. SSG, ISG로 인해 노드환경상에서도 쓰일수가 있기 때문에 체크가 필요하다.

    set 할때도 마찬가지

    export const saveToStorage = (key:string, value:string) => {
        if(typeof window !== 'undefined') {
            return window.localStorage.setItem(key, value);
        }
    }

     

    문제2) useEffect로 호출할때 문제 발생.

    export const AuthApiClient = axios.create({
        baseURL: "http://localhost:3001",
        withCredentials: true,
        headers: {
            'Content-type': 'application/json',
            'Authorization': 'Bearer '+getFromStorage('accessToken')
        },
        transformRequest:[
            (data) => {
                return JSON.stringify(data);
            },
        ],
        transformResponse: [
            (data) => {
                return JSON.parse(data);
            },
        ],
    })
    
    export const getFromStorage = (key:string) => {
        if (typeof window !== 'undefined') {
            return window.localStorage.getItem(key);
        }
    }

    Nextjs 특성상 Authorization에 들어가는 accessToken을 getFromStorage로 호출해서 사용 하려고 했으나

    localStorage is not defined

    이런식으로 에러뜸. 

     

    Next.js가 화면을 렌더링하는 원리

    (1) Pre-rendering

    브라우저에서 yarn dev로 접속을 하면
    yarn dev(프론트엔드 서버) 프로그램 자체에서 html, css, js를 브라우저에 전달하기 전에 소스코드를 먼저 돌려본다.

    사전에 먼저 한번 그려본다고 해서 프리렌더링이라고 한다.
    이때 모든 것을 완벽하게 그리는 것은 아니다. 전체적인 구조만 그림을 그린다.
    (useEffect 같은 mount 되고 나서 실행되는 것들은 빼고!
    onClick, onChange 등의 바인딩도 빠져있다.)

     

    (2) hydration

    프리렌더링 이후에 html, css, js를 브라우저로 보내주면 브라우저에서 제대로 그림을 그리고, 여기서 그린 그림과 프리렌더링할때 그린 그림을 비교해서(diffing) 최종 완성형으로 업데이트 해준다.
    diffing 이후 최종 완성형으로 업데이트 될 때 onClick, onChange 등이 반영된다.

    diffing 이후에 최종 완성형으로 업데이트 해주는 과정을 hydration이라고 한다.
    (hydration: onClick 등이 빠져있는 정적인 데이터에 물기를 줘서 움직일 수 있게 해준다는 의미)

     

    Local Storage, Session Storage 등은 브라우저에 있는 것이다.프리렌더링을 할 때는 (프론트엔드 서버에는) Local Storage라는 개념이 없다.
    즉, 프론트엔드 서버에서 yarn dev해서 실행될 때(Pre-rendering)는Local Storage라는 개념이 없어서 위에서 localStroage를 찾을 수 없다는 에러가 나온 것이다.

     

    해결방법

    localstorage가 pre-rendering에서 실행 되지 않도록 막는다.

    // _app.tsx
    useEffect(() => {
        if(getFromStorage('accessToken')) {
          const accessToken = getFromStorage('accessToken');
          checkUser(accessToken ? accessToken : "");
        }
      },[]);
      
    
    //userService.tsx
    export const checkUser = async(accessToken:string) => {
    
    	AuthApiClient.defaults.headers.common['Authorization'] = `Bearer ${accessToken}`;
    	const response = await AuthApiClient.get(`/users/checkUser`);
    
    	return response;
    }
    
    export const AuthApiClient = axios.create({
        baseURL: "http://localhost:3001",
        withCredentials: true,
        headers: {
            'Content-type': 'application/json',
        },
        transformRequest:[
            (data) => {
                return JSON.stringify(data);
            },
        ],
        transformResponse: [
            (data) => {
                return JSON.parse(data);
            },
        ],
    })
    이렇게 하면 로그인 후 새로 고침 해도 accessToken을 가지고 user를 check 할 수 있다.

     

    Nextjs에서 headers에 authorization으로 Local Storage 에 있는 accessToken을 포함시켜서 보내려면 이런식으로 해야된다.

    728x90

    'Next.js' 카테고리의 다른 글

    Nextjs 보일러 프로젝트 생성 뼈대  (0) 2023.01.10
    tsconfig.json 설정  (0) 2023.01.10
    Recoil, react-query 로그인 오류  (0) 2022.12.24
    [Nextjs]SSG,SSR react-query로 Dynamic Routes에 적용  (0) 2022.12.22
    [Nextjs]상태관리  (2) 2022.12.22
Designed by Tistory.