항해 99

항해 99 10주차를 끝내며

세발낙지 2022. 3. 21. 10:56

    이번 주는 소셜 로그인을 최정적으로 마무리짓고, 소켓 통신에 대해서 알아보고 구현해보았다. 내가 당담하는 백엔드 쪽에서 계속 api 구축 계획이 늦춰지면서 전체적으로 팀의 진행 상황이 딜레이되고 점점 미궁 속으로 빠지는, 참으로 미안하고 괴로운 한 주였다. 

 

    그 사이 토큰을 다루는 로직이 조금 변화했다. 처음 구현하려 했던 방향은, 모든 요청에 대해서 엑세스 토큰을 재발급해주는 것이다. 즉, 엑세스 토큰만을 이용한 요청에 대해서도 새로운 엑세스 토큰을 다시 발급하는 것이다. 유효기간이 많이 남은 엑세스 토큰을 왜 재발급해 주는 이유는 유저가 최대한 엑세스 토큰만으로 요청을 처리하는 것이 사용자 경험에 좋을 수 있다고 판단했기 때문이다. 엑세스 토큰과 리프레시 토큰을 사용하여 구현하는 로그인의 경우, 필연적으로 엑세스 토큰이 만료되었을 때 서버에 최소 2회의 요청이 필요하다. 또한, 리프레시 토큰을 활용하여 요청을 처리하게 되는 경우에는 백엔드 서버 입장에서 데이터베이스에 접근하여 이를 대조해야 하므로 단순히 엑세스 토큰만을 활용할 때보다 소요되는 시간이 더 길다. 이를 최소화하기 위해 마치 세션과 쿠키를 활용한 로그인 방식처럼 사용자의 모든 행동이 엑세스 토큰의 만료기한을 연장토록 하고, 엑세스 토큰의 활용성을 극대화할 수 있을 것이라 판단했다. 

 

    또한, 현재 사용 중인 nestjs에서는 rxjs라이브러리로 구현된 observable 객체를 활용하여 interceptor가 구현되어 있다. 잘 모르는 상태에서 최대한 짧게 말하자면, Observable 객체는 Promise 객체와 비슷한 듯 다른데, 이것은 두가지 특징에서 그렇다. 첫번째로 Promise 객체는 중간에 취소가 불가능하지만, Observable 객체는 취소가 가능하다는 것이고, Promise 객체는 중간에 값이 변할 수 없지만, Observable 객체는 값이 변화할 수 있다는 것이다. 바로 Observable의 이런 점을 활용하여 request가 들어왔을 때, 엔드 포인트에 있는 라우터에서 콜백함수가 실행되기 전후로 interceptor가 작동할 수 있다. NestJs에서의 Request lifecycle을 보면 다음과 같다.

Request Lifecycle in NestJS 출처:https://chuongtrh.github.io/post/request-lifecycle-in-nestjs/

최초에 이런 그림을 통해 interceptor의 존재를 접했을 때에는, Observable 객체에 대해서 전혀 모르는 상황에서 알게 되었기 때문에 라우터에서 요청이 처리되기 전후로 존재하는 interceptor가 서로 다른 것이라고 이해했지만, 이번에 모든 요청에 대해서 엑세스 토큰을 발급해주기 위해서 guard와 interceptor에 대해서 공부하는 중에 알게 된 사실이다. 

 

    두번째로 구현을 해본 것은, 엑세스 토큰을 발급할 때 만료 시간을 함께 발급하고, 클라이언트에서 이 시간에 맞추어 새로운 엑세스 토큰 발급을 요청하는 것이다. 이 때, 새로운 엑세스 토큰을 리프레시 토큰을 활용하여 발급 요청한다. 이렇게 되면 유저가 엑세스 토큰이 새로 발급되는 것을 실질적으로 느낄 수 없을 것이고, 사용자 경험에 더 좋을 것이라고 생각했다. 첫번째 방법에서 사용자가 체감하는, 리프레시 토큰을 활용한 엑세스 토큰 재발급 과정을 더 줄인 것이다. 그러나, 이 방법에 대해서 멘토님께 여쭈었을 때 추후에 서비스가 커지고 난 후에 탈취당한 엑세스 토큰에 대한 처리 작업을 구현할 때, 특정 토큰에 대해서 백엔드 서버에서 거부 처리를 할 수 있고, 이렇게 되는 경우에는 프론트엔드 서버에서 예상하지 못하는 에러가 반환될 수 있어 문제가 될 수 있다고 하셨다. 최종적으로는 리프레시 토큰을 활용하여 요청이 들어왔을 경우에만 엑세스 토큰을 발급해주는 방식으로 진행될 것 같다.

 

    웹소켓을 활용한 단체 채팅방과 실시간 알림을 구현하기 위해 공부하고 있다. 웹소켓의 경우, 일부 구형 브라우저는 정상적으로 지원하지 않고, 고전적인 형태의 양방향 통신인 풀링 방식만을 지원하여 이 부분에 대해서 따로 예외처리를 해주어야 한다. 그러나, nodejs의 socketIO 라이브러리를 활용하면, 이 부분에 대해서 자동적으로 처리가 진행되어 편리하게 실시간 통신을 구현할 수 있다. 소켓을 활용한 통신은 기본적으로 이벤트를 통해 진행된다. 예를들어 클라이언트에서 어떤 이벤트를 발생시키면, 서버에서 이를 감지하여 특정 동작을 수행하고 다시 이벤트를 발생시킬 수도, 처리된 값을 전송할 수도 있는 것이다. 단, 소켓 통신의 경우 모든 데이터 전송은 문자열의 형태로 이루어져서 이 부분에 대한 parsing이 필요하다. 물론, SocketIo 라이브러리를 이용하는 경우에는 자동적으로 이런 부분을 해결해준다.

 

출처

1. Nest.JS Official Document - Request Lifecycle

 

Documentation | NestJS - A progressive Node.js framework

Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Progamming), FP (Functional Programming), and FRP (Functional Reac

docs.nestjs.com

 

'항해 99' 카테고리의 다른 글

항해 99 12주차를 끝내며  (0) 2022.04.04
항해 99 11주차를 끝내며  (0) 2022.03.28
항해 99 9주차를 끝내며  (0) 2022.03.15
항해 99 8주차를 끝내며  (0) 2022.03.07
항해 99 7주차를 끝내며  (0) 2022.02.28