inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스

따로 분리한 getAccessToken() 함수 result의 타입

해결된 질문

725

ju han

작성한 질문수 15

1

강의를 보고 똑같이 따라했지만 저는 result에 타입이 unknown이라고 뜨네요.

이때문인지는 모르겠지만 로그인 후 넘어간 페이지에서 버튼 누르는 과정에서 오류가 뜹니다.ㅜ

아래는 아폴로 세팅입니다. 문제가 무엇일까요?

import {
  ApolloClient,
  ApolloLink,
  ApolloProvider,
  fromPromise,
  InMemoryCache,
} from "@apollo/client";
import { onError } from "@apollo/client/link/error";
import { createUploadLink } from "apollo-upload-client";
import { useEffect } from "react";
import { useRecoilState } from "recoil";
import { getAccessToken } from "../../../commons/libraries/getAccessToken";
import { accessTokenState } from "../../../commons/store";

const GLOBAL_STATE = new InMemoryCache();


interface IApolloSettingProps {
  children: JSX.Element;
}

export default function ApolloSetting(props: IApolloSettingProps) {
  const [accessToken, setAccessToken] = useRecoilState(accessTokenState);
  

  // 3. 프리랜더링 무시 - useEffect
  useEffect(() => {
    console.log("지금은 브라우저다");
    const result = localStorage.getItem("accessToken");
    console.log(result);
    if (result) setAccessToken(result);
  }, []);

  // 에러를 캐치하고 캐치한 에러가 토큰만료면 재발급 받은 후, 기존의 쿼리를 포워드해서 다시 날려준다.
  const errorLink = onError(({ graphQLErrors, operation, forward }) => {
    // 1-1. 에러를 캐치
    if (graphQLErrors) {
      for (const err of graphQLErrors) {
        // 1-2. 해당 에러가 토큰만료 에러인지 체크(UNAUTHENTICATED)
        if (err.extensions.code === "UNAUTHENTICATED") {
          return fromPromise(
            // 2-1. refreshToken으로 accessToken을 재발급
      
            getAccessToken().then((newAccessToken) => {
              // 2-2. 재발급 받은 accessToken 저장하기
              setAccessToken(newAccessToken);

              // 3-1. 재발급 받은 accessToken으로 방금 실패한 쿼리의 정보 수정하기
              if (typeof newAccessToken !== "string") return;
              operation.setContext({
                headers: {
                  ...operation.getContext().headers, // 만료된 토큰이 추가되어 있는 상태
                  Authorization: `Bearer ${newAccessToken}`, // 토큰만 새것으로 바꿔치기
                },
              });
            })
          ).flatMap(() => forward(operation)); // 3-2. 방금 수정한 쿼리 재요청하기
        }
      }
    }
  });

  const uploadLink = createUploadLink({
    uri: "https://backendonline.codebootcamp.co.kr/graphql", // https 로 변경(토큰 정보를 쿠키에 담을 수 있게)
    headers: { Authorization: `Bearer ${accessToken}` },
    credentials: "include", // https 변경으로 추가된 조건
  });

  const client = new ApolloClient({
    link: ApolloLink.from([errorLink, uploadLink as unknown as ApolloLink]),
    // cache: new InMemoryCache(),
    cache: GLOBAL_STATE,
  });

  // prettier-ignore
  // 주석으로 prettier-ignore 해주면 한줄로 바뀌는걸 막아준다
  return <ApolloProvider client={client}>
    {props.children}
    </ApolloProvider>;
}

혹시 이부분때문일까요??

link: ApolloLink.from([errorLink, uploadLink as unknown as ApolloLink])

react node.js seo graphql next.js

답변 1

0

코드캠프 프론트엔드 멘토

안녕하세요!

해당 오류는 백엔드 서버에서 refreshToken이 새로운 토큰을 재발급해주는 로직이 잘못되어 토큰바꿔치기가 안되어 발생하는 오류입니다.
따라서 해당 부분을 보완한 서버로 바꿔주셔야 합니다.

uploadLink와 getAccessToken() 부분에 주소를 아래 주소로 바꿔주세요!
https://backend-practice.codebootcamp.co.kr/graphql

감사합니다.😁

0

ju han

감사합니다!! 수정하니까 되네요!!

그런데 또 궁금한점이 있습니다.

수업노트에 보면 아래처럼 예시를 보여주시는데,

// src/apollo/index.tsx 파일

export default function ApolloSetting(props: IApolloSettingProps) {
  const [accessToken, setAccessToken] = useRecoilState(accessTokenState);
  const [userInfo, setUserInfo] = useRecoilState(userInfoState);
	if (!accessToken || !userInfo) return;
	    setUserInfo(JSON.parse(userInfo));
	  }, []);
	
	const errorLink = onError(({ graphQLErrors, operation, forward })=>{
		// 1-1. 에러를 캐치

		// 1-2. 해당에러가 토큰만료 에러인지 체크(UNAUTHENTICATED)		

    // 2-1. refreshToken으로 accessToken을 재발급 받기
				
		// 2-2. 재발급 받은 accessToken 저장하기

		// 3-1. 재발급 받은 accessToken으로 방금 실패한 쿼리정보 수정하기

		// 3-2. 재발급 받은 accessToken으로 방금 수정한 쿼리 재요청하기

	})

	  const uploadLink = createUploadLink({
	    uri: "http://backendonline.codebootcamp.co.kr/graphql",
	    headers: { Authorization: `Bearer ${accessToken}` },
		  credentials: "include",
	  });
	
	  const client = new ApolloClient({
	    link: ApolloLink.from([uploadLink]),
	    cache: APOLLO_CACHE,
	    connectToDevTools: true,
	  });
	

	  return (
	    <ApolloProvider client={client}>
	        {props.children}
	    </ApolloProvider>
	  )
	}

 

아래 두 부분은 수업에서 진행하지 않았던 것 같은데

  1. userInfo 글로벌스테이트에 저장하는 부분

  2. client 설정에 connectToDevTools 부분

혹시 어떻게 추가가 된건지 알 수 있을까요?

 const [userInfo, setUserInfo] = useRecoilState(userInfoState);
  const client = new ApolloClient({
	    link: ApolloLink.from([uploadLink]),
	    cache: APOLLO_CACHE,
	    connectToDevTools: true,
	  });

fetchBoardsOfMine, fetchBoardsCountOfMine 에러 문의드립니다

0

41

1

댓글 기능 구현 중 질문드립니다.

0

67

1

쿠폰코드 발급

0

147

2

example 서버 플레이그라운드, API 접속 모두 안됩니다.

0

89

2

문의드립니다!! ㅠㅠ

0

107

2

graphql 백엔드 서버가 포폴용 빼곤 접속이 안됩니다.

0

80

2

_app.js 작성 이후로 에러가 발생하네요

0

96

2

학습자료

0

72

2

학습자료가 안열립니다.

0

51

2

플레이 그라운드 퀴즈 문제 질문이 있습니다.

0

61

0

기존강의 구매자, 업데이트 끝인가요?

0

111

3

업데이트 버전 수강

0

89

2

완벽한 프론트엔드

0

136

2

나만의 쇼핑몰 샘플 페이지 접속 확인부탁드립니다.

0

84

1

graphql 접속이 안됩니다.

0

101

2

const, let 사용 질문 드립니다.

0

72

2

싸이월드 만들기 1탄 피드백 부탁드립니다.

0

123

2

회원가입 과제 피드백 부탁드립니다.

0

81

2

styled.span / styled.input "CSS 자동완성"

0

47

1

쿠폰 발급 관련

0

167

2

서버 502 error

0

247

2

쿠폰 다시 부탁드려도 될가여?

0

140

2

a태그 패딩했을때 왜 크기가 줄어들지 않고 늘어나나요

0

185

2

2분 44초 질문

0

132

3