React Native - 8 - request/response 미들웨어 토큰 관리 및 성능 저하 개선 정보
React Native - 8 - request/response 미들웨어 토큰 관리 및 성능 저하 개선본문
그누보드5 api는 jwt token을 통해 회원 인증을 하고 있습니다.
유저 편의성을 위해 access token 만료시에 refresh token을 통해 재로그인 없이 갱신을 할 수 있도록
axios 라이브러리의 interceptors 기능을 사용하고 있습니다.
로그인 여부에 따라서 읽을 수 있는 글의 권한, 글 작성 권한, 프로필 수정 등이 다르게 처리가 되어야하기
때문에 아래와 같은 방식으로 처리가 되고 있었습니다.
1. 비회원 (jwt token 없이) request
-> Header에 token 없이 request (token이 필요 없는 request만 처리 가능)
2. 회원 request
1) access token 만료
-> access token 만료시 401 token 만료 에러 response
-> 기기에 저장하고 있는 refresh token을 불러와서 access token 재발급
-> 재발급 받은 access token을 통해 401 에러가 났던 request 재요청
2) refresh token 만료
-> access token 만료로 refresh token을 통한 토큰 재발급 요청을 하는데, 이 과정에서
refresh token 역시 만료되는 경우, 토큰을 지우고 비회원과 같은 상태로
401 error를 받은 request를 재요청
위와 같은 토큰 처리 과정에서 3가지 문제상황이 있었습니다.
1. 하나의 페이지에서 여러 request가 발생하는 경우, access token 만료시 재발급 요청시에 사용되는
refresh token이 변경되는 문제
2. refresh token 만료시에 토큰을 지우고 재요청시에 error 발생
3. 회원 request가 비회원 request에 비해 상당히 속도가 느려지는 현상 발생
1번의 경우 하나의 페이지를 구성하는 여러 request가 동시에 발생했을 때,
access token만료시 토큰 재발급 요청을 여러번 하는 경우 문제가 발생했습니다.
refresh token을 통해 토큰을 재발급하면 기존 refresh token 역시 새롭게 변경되는데,
후속 재발급 요청이 만료된 refresh token을 통해서 token 재발급 요청을 하는 문제가 있었습니다.
변경내용: 첫 request를 통해서만 토큰을 재발급하고, 후속 request들은 대기상태의 배열에 넣어서,
토큰 발급이 모두 완료되었을 떄 새로운 토큰을 가지고 대기하던 request를 하도록 수정.
2번의 경우 첫 request가 error response를 받은 후,
토큰을 삭제하고 재요청하는 request가 첫 request와 일치하지 않아서 생기는 문제였습니다.
위 상황에서 request들은 다음과 같이 됩니다.
request1 -> response1: 401 error
request2 (token refresh) -> response2: 토큰 만료로 인한 error
request3: token을 삭제하고 실패한 request 재요청
request1이 실패후 토큰을 재발급 하는 request2가 실패했기 때문에,
request3에서 재요청하는 request는 원래 의도였던 request1이 아닌
request2 (token 재발급 요청)가 되는 문제가 있음을 발견했습니다.
변경내용: 클라이언트 단에서 로그인 상태이지만 토큰이 모두 만료된 경우,
새로 로그인을 하도록 알림을 띄우고 홈 스크린으로 이동하는 로직으로 변경하였습니다.
3번 문제의 경우, react의 특성을 제대로 파악하지 못해서 발생한 이슈였습니다.
axios interceptors에서, 모든 토큰이 만료된 경우 logout함수를 통해 로그아웃을 시켜줘야 했고,
logout 함수는 useAuth라는 커스텀 훅을 통해 불러올 수 있도록 작성되어 있습니다.
이 logout 함수를 interceptors에서 인자로 받기 위해,
interceptors를 컴포넌트의 useEffect 단에서 초기화하도록 되어있었습니다.
문제 상황 발생: useEffect가 반복적으로 실행됨에 따라
request가 여러차례 반복되는 문제로 인해 성능저하 이슈가 있었습니다.
변경내용: logout함수를 interceptors에서 인자를 통해 받는 것이 아니라,
변수를 선언하고, 해당 변수에 logout함수의 reference를 할당하는 방식으로 변경하였습니다.
작업내역:
[fix/improve] request inteceptors 다수의 중복 요청 수정
[fix] response interceptors 컴포넌트에서 제외
[improve] request interceptors getTokens() - 토큰 없는 경우만 실행
[fix] 리프레시 토큰 만료 조건 수정, 예외처리 추가
[fix] 동시적인 token 갱신 요청시 발생 오류 수정
[refactor] response interceptors logout 함수 확인 로직 이동
[fix] response interceptors 토큰만료 로그아웃시 전역변수 초기화
1
댓글 1개
몇 주간 그리고 글까지 남겼던 내용이 RN에 업데이트 되었고
제가 고민했던 부분까지 그대로 녹여져 있네요.
고생하셨습니다.
제가 구현한, 인터셉트입니다. 뭐 RN은 제가 잘 모르지만..
소스보니 얼추 비슷하게 흘러가는 형태더군요..
저는 401 떨어지면, 리뉴얼 요청 > 승인 > 위에 본문에 있는 것 처럼 다시 그 주소로 리퀘스트 날리기..
FLASE > 로그아웃 형태입니다.
RN은 모바일이니 그럴수 있지만, WEB의 경우는 임의로 쿠키나 스토리지에 장난질(?) 하는것 까지 감안해야 하다보니, 머리가 아프네요
짜피 장난질 해도 실제 승인(글등록/댓글등록)은 안나겠지만,
이걸 실시간 감지 하느냐 ? 그냥 어떠한 액션이 있을 때 감지하느냐?를 두고 많이 고민했었습니다.
소스코드 보다 에싱크 스토리지라는걸 첨봤는데, RN이군요.. ㅎ
크로스 플랫폼인 만큼 안드로이드 + IOS 에서도 그누5 RN 버전을 만나볼 수 있길 바랍니다.