사내에서 차량의 위치 정보를 실시간으로 받아오는 기능 개발이 필요했다.
해당 기능을 구현하기 위해서는 어떤 방법들이 있는지, 그리고 실제로 어떤 방법으로 구현을 했는지 정리해보고자 한다.
구현 필요 기능 명세
다수의 차량 위치정보를 실시간으로 화면에 출력해주는 기능이 필요했습니다.
각 차량의 정보를 수신하는 주기는 500ms으로 생각하고 있었으며, 최대 차량의 개수는 100대 였습니다.
일반적인 HTTP 통신을 하게 되면 클라이언트 측 부담이 커지게 때문에, 서버쪽에서 바로 차량 위치 정보를 보낼 수 있는 방향으로 가닥을 잡았습니다.
서버가 클라이언트에게 데이터를 보내면 클라리언트가 이를 인지하고, 데이터 처리를 해주는 방법은 크게 WebSocket과 SSE 두 가지가 존재합니다.
WebSocket vs SSE(Server-Sent-Events)
두 방식 모두 대부분의 모던 브라우저에서 지원되고 있기 때문에, 차이점은 아래와 같고 주요하게 고려할 부분은
통신 방향, 데이터 형태와 최대 동시 접속 수에 있습니다.
웹소켓 | SSE | |
통신방향 | 양 방향 | 단 방향(서버 ➡ 클라이언트) |
최대 동시 접속 수 | 브라우저 연결 한도 없음 | HTTP - 브라우저 당 연결 한도 6개 HTTP2 - default 100개 |
데이터 형태 | Binary, UTF-8 | UTF-8 |
자동 재접속 | NO | Yes(3초) |
프로토콜 | 웹소켓 | HTTP |
배터리 소모량 | 큼 | 작음 |
나의 경우, 서버 쪽에서 보낸 데이터를 수신만 하면 되는 경우였고, 바이너리 데이터를 받을 것도 아니었기 때문에 SSE 방식을 선택하게 되었다.
SSE 구현(feat. Vue)
SSE를 구현하기 위해서는 서버쪽에서 데이터를 보내주는 부분을 구현해줘야 하지만, Client 쪽에서는 매우 간단하게 구현 할 수 있다.
SSE 구현은 크게 아래 4가지로 구분 할 수 있다.
- EventSource 생성
- 서버에서 이벤트 받기
- 에러 핸들링
- 연결 종료
1. EventSource 생성
Server-Sent Event API는 EventSource (en-US) 인터페이스에 포함돼 있다. 따라서 이벤트를 받기 위해 서버에 접속을 하려면 가장 먼저 EventSource 객체를 생성해주어야 한다.
const sseConnection = ref<EventSource | null>(null);
sseConnection.value = new EventSource(url, { withCredentials: true })
url은 연결하고자 하는 서버의 url을 입력해주면 된다.
withCredentials은 서로 다른 도메인(Cross Domain)에 요청을 보낼 때, credential 정보를 함께 보낼지를 의미한다.
나는 백엔드와 프론트엔드 도메인이 다르기 때문에, true로 설정해주었다.
나중에 서버연결을 종료할 때, EventSource가 필요하기 때문에, 변수에 저장해둔다.
2. 서버에서 이벤트 받기
서버에서 이벤트를 수신했을 때, 처리하는 함수를 onmessage에 핸들러로 설정해주면 된다.
function sseMessageHandler({data}: {data: string}){
// stringified된 JSON으로 넘어오기 때문에, parse해준다.
// 여기에서 원하는 타입으로 변환 해 준다.
const someDatas = JSON.parse(data) as TestType;
//여기에서 data 처리를 한다.
}
// 앞서 생성해 둔 EventSource 객체의 onmessage에 핸들러로 등록해준다.
sseConnection.value.onmessage = sseMessageHandler;
3. 에러 핸들링
앞서 처리한 방식대로 에러 핸들링 함수도 등록해준다.
function sseErrorHandler(e){
console.log("ERROR OCCURED!")
}
sseConnection.value.onerror = sseErrorHandler;
4. 연결 종료
연결이 더 이상 필요 없는 경우, 반드시 연결을 종료해준다.
onBeforeUnmount(() => {
sseConnection.value.close()
})
나의 경우, SSE를 사용하는 컴포넌트가 종료되기 전에 종료 해주는 방식으로 구현했다.
'Vue' 카테고리의 다른 글
[Vue] vue-cli에서 vite migration 전체 가이드 (0) | 2023.12.20 |
---|---|
[Frontend]이미지 로드 시간 줄이기 (0) | 2023.12.11 |
[Vue3] 'defineProps' is not defined 해결 (0) | 2023.11.27 |
drag drop 가능한 file type input 커스텀하기(feat. vue3) (0) | 2023.11.24 |
[Vue] Toggle Switch 만들기 (feat. Atomic Design) (0) | 2023.11.08 |