개요
백엔드를 주 개발을 하면서 뷰까지 개발하게 되면 `SSR`을 사용하게 되는데, 이러한 `SSR`을 사용하게 되면 문제는 실시간으로 반영되는 데이터를 유저에게 보여줄 수 없다는 것입니다. 그렇다면 유저는 당연하게도 원하는 데이터를 화면에서 보기 위해서 페이지 새로고침을 해야 한다는 것입니다. 이러한 문제를 해결하기 위해서 사용되는 방식은 `SSE`와 웹소켓인데 이번 그 중에서 `SSE`를 `Nest.js`로 구현하면서 이해 해보고자합니다.
SSE vs Web Socket
기술을 사용하기 전에 실시간 통신을 하기위해 사용되는 `SSE`와 `Web Socket`은 어떠한 차이가 있는지 알아 보고자 합니다.
SSE
- `단방향 통신` : SSE는 오로지 서버에서 클라이언트 쪽 서버로만 데이터를 보낼 수 있는 구조이다.
- `자동 재연결` : 서버와의 연결이 끊어지면 자동적으로 재연결을 시도한다.
- `간단한 구조` : 클라이언트에서는 EventSource 라는 인터페이스를 사용하면 쉽게 데이터를 구현 할 수 있다.
Web Socket
- `양방향 통신` : 서버와 클라이언트 측 둘 다 데이터를 보낼 수 있는 구조이다.
- `수동 재연결` : 연결이 끊어진 경우 수동으로 재접을 해야 한다.
이러한 특성을 파악하여 어떠한 서비스를 만들어야 하는가에 따라 `SSE`와 `Web Socket`을 선택적으로 활용하여 구현을 할 수 있도록 하면 되겠습니다.
코드 구현
`Nest.js` 프레임워크에서 `SSE`를 쉽게 구현 할 수 있도록 제공을 하고 있습니다. 컨트롤러에서 `@Sse()` 데코레이터를 사용하면 쉽게 구현이 가능토록 하였는데 어떻게 구현하는지 코드를 보도록 하겠습니다.
@Controller()
export class AppController {
private dataStream = new Subject<any>();
constructor(private readonly appService: AppService) {}
@Sse('sse')
sse(): Observable<MessageEvent> {
return interval(1000).pipe(
map((_) => ({ data: { hello: 'world' } } as MessageEvent)),
);
}
}
`rxjs`에서 제공하는 파이프 함수를 이용해 각 데이터를 매 초마다 전송하도록 하고 있습니다. 이러한 서버를 구축한 이후에는 클라이언트 측 서버에서 확인 할 수 있도록 코드를 작성하여야 합니다. 위에서 설명하였듯이 `EventSource`를 사용하면 쉽게 데이터를 얻을 수 있습니다.
현재는 `static` 파일을 제공하는 모듈을 설치하고 `public/index.html` 파일을 유저에게 제공하는 서버를 구축을 우선 하여야 합니다.
`static` 파일을 제공하기 위해서 `@nestjs/serve-static` 모듈을 설치 해야 합니다
npm install @nestjs/serve-static
그리고 `index.html` 파일내에 `script` 문을 작성해주어야 합니다.
<script type="text/javascript">
const eventSource = new EventSource('/sse');
eventSource.onmessage = ({ data }) => {
const message = document.createElement('li');
message.innerText = 'New message: ' + data;
document.body.appendChild(message);
};
</script>
이러한 준비가 완료가 되면 서버가 가동되는 서버의 url에 index.html을 붙여 주게 되면 다음과 같은 화면을 볼 수 있습니다.
매 초 마다 데이터를 보내게 되면서 이러한 결과를 볼 수 있겠습니다.
이번에는 동적인 데이터를 SSE로 전달하는 방식을 보겠습니다.
@Controller()
export class AppController {
private dataStream = new Subject<any>();
constructor(private readonly appService: AppService) {}
@Post('data')
getData(@Body() body: any) {
this.dataStream.next({ data: body });
return {
data: body,
};
}
@Sse('sse')
sse(): Observable<MessageEvent> {
return this.dataStream
.asObservable()
.pipe(map((data) => ({ data } as MessageEvent)));
}
}
`Post`요청으로 `body`를 보내게 되면 해당 데이터를 `dataStream`을 통해 `SSE` 서버용 컨트롤러 까지 전달을 하게 됩니다.
이러한 구조에 대한 이해를 하고 요구사항에 맞춰 사용할 수 있다면 유저에게 좀 더 좋은 경험과 기능을 제공하는 서비스를 제공할 수 있는 기술이라고 생각합니다.
'Backend > Nest.js' 카테고리의 다른 글
Nest.js Bull (0) | 2023.12.05 |
---|---|
Nest.js Integration Test 와 Mocking (1) | 2023.10.10 |
Nest.js mongodb-memory-server, cache 적용 (1) | 2023.10.05 |
Nest.js Rate Limiting 설정 (0) | 2023.09.30 |
Nest.js Swagger 보안 설정 (0) | 2023.09.30 |