반응형
안녕하세요 ! 오늘의 포스팅은 "SSE"에 대한 글입니다. 제목 어그로를 한번 끌어봤는데요?
어그로가 맞긴 하지만 실제로 저는 SSE를 알게 된 후로 개발의 질이 높아졌기 때문에 완전히 어그로는 아니랍니다^_^
진행률을 클라이언트에게 전달해야 하는 상황이라면, 어떻게 하실건가요?
(feat. 서버의 이벤트를 클라이언트에게 전달하는 방법)
서버가 클라이언트에게 진행률을 알려줘야 하는 상황입니다. 어떻게 구현 할 수 있을까요?
1. polling , Long polling
- 클라이언트가 일정 주기마다 http reqeust 를 서버로 계속 보내 이벤트 내용을 전달 받는 방식
- Long polling 은 말 그대로 일정 주기를 길게 잡는 방식, 그 외의 차이점은 없음
- 클라이언트가 지속적으로 request를 보내기 때문에 클라이언트가 많아지면 서버의 부담이 급증함
- 실시간 정도의 빠른 응답을 기대하기 어려움
- 일정하게 갱신되는 서버 데이터의 경우 유용할 순 있음
- 구현이 쉽다(?) , 웹 개발자인 나로써는 무의미한 요청들을 눈뜨고 볼 수가 없음 (개인적인 생각입니다^^..)
2. Websocket
- 양방향 채널을 이용해 양방향 통신이 가능
- 기존 http 요청 응답 방식은 요청한 그 클라이언트에만 응답이 가능했지만, ws 프로토콜을 통해 웹소켓 포트에 접속해 있는 모든 클라이언트에게 이벤트
방식으로 응답이 가능함. - 최초 접속이 일반 http reques를 통해 handshking 과정을 통해 이루어지기 때문에, 기존 포트로 접속을 하므로 추가로 방화벽을 열지 않고도 양방향 통신이 가능하고, http 규격인 CORS적용이나 인증등의 과정을 기존과 동일하기 가져갈 수 있는 점이 장점임
3. SSE(Server-Sent Event)
- HTML5 표준안이며 어느정도 웹소켓의 역알을 하면서 더 가벼움
- server-> client 단방향이기 때문에 서버의 이벤트나 메세지를 클라이언트로 전달하는 작업에서 유용하게 사용
- 재접속 처리 같은 대부분의 저수준 처리가 자동으로 지원
- 3초마다 재접속 시도
- SSE의 경우 TTP2를 사용하지 않을 경우에는 브라우저에서 6 정도로 제한하고 있음
- 앞으로도 크롬이나 파이어폭스에서는 고치지 않을 예정이라고함.
- 단, HTTP2를 상요하면 기본으로 100개를 허용한다함.
SSE 구현하는 방법
SSE로 서버가 클라이언트에게 1부터 10까지 전달하는 예제 코드를 작성해보겠습니다
Server - springboot, java
package com.example.demo;
import lombok.SneakyThrows;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
@RestController
@CrossOrigin("*")
public class SSEController {
private SseEmitter mySse;
@GetMapping(value = "/connect/sse")
public SseEmitter connectSSE(){
System.out.println("SSE 연결 완료 됐습니다.");
mySse = new SseEmitter(99999L); // sse 인스턴스 생성
mySse.onTimeout(new Runnable() { // 타임아웃 처리
@SneakyThrows
public void run() {
System.out.println("SSE 타임아웃 입니다.");
}
});
return mySse;
}
@GetMapping(value = "/test/sse")
public ResponseEntity<?> test() throws IOException {
for(int i = 1 ; i<=10; i++){
mySse.send(i);
}
System.out.println("모든 데이터 전달을 완료 하였습니다. sse 연결을 종료합니다.");
mySse.complete(); // 연결 종료
return new ResponseEntity<>("success", HttpStatus.OK);
}
}- 참고로 SseEmitter 객체를 생성 할 때 timeout 파라미터 값에 아무 값도 입력하지 않을 시 timeout의 값은 null 임

- timeout 파라미터에 값을 입력하지 않은 경우, sse 연결 후 30초 뒤에 타임아웃 이벤트 발생.
@GetMapping(value = "/connect/sse")
public SseEmitter connectSSE(){
System.out.println("SSE 연결 완료 됐습니다. " + LocalDateTime.now().toString());
mySse = new SseEmitter();
System.out.println("타임아웃 시간 : " + mySse.getTimeout());
mySse.onTimeout(new Runnable() {
@SneakyThrows
public void run() {
System.out.println("SSE 타임아웃 입니다." + LocalDateTime.now().toString());
}
});
return mySse;
}- 위 코드의 실행 결과는 아래와 같습니다. 결과를 확인해보면 연결 후 30초 뒤에 타임아웃 이벤트가 발생함을 확인 할 수 있습니다.

위의 코드 실행 결과
client - js, 브라우저 콘솔창에서 테스트 했음
let eventSource = new EventSource("http://localhost:8080/connect/sse");
// 접속이 맺어졌을 때 호출
eventSource.onopen = event => {
console.log("connection opened");
};
// 기본 메세지가 왔을 때 호출
eventSource.onmessage = event => {
console.log("result", event.data);
};
// 오류 발생 시 호출
eventSource.onrror = event => {
console.log("error");
};결과

마치며
회사에서 진행하는 프로젝트에서 진행률, 실시간으로 분석되는 결과를 클라이언트에게 전달 할 때 SSE를 사용하고 있습니다.
SSE 를 알기 전까지는 웹소켓으로 진행했었기 때문에 개인적으로는 테스트도 어렵고 구현도 어려워서 애를 많이 먹었습니다.
물론 제가 웹소켓에 대한 이해력이 부족했기 때문이겠지만요 ^_^
웹소켓으로 애를 먹던 와중 직장 동료가 SSE라는게 있다고 알려줬고, 저는 그날 한줄기 빛을 발견한 기분이였습니다.
SSE를 알게 된 후 더이상 저는 실시간으로 정보 전송 기능을 구현함에 있어서 쫄지 않을 수 있었어요
이 글을 읽으시는 분들도 저 처럼 진행률이나 실시간 결과를 클라이언트에 전달 해야 한다면 SSE를 사용해보시는걸ㄹ 추천합니다 👍🏻
반응형
'Dev > Web' 카테고리의 다른 글
| Nginx (0) | 2023.07.26 |
|---|---|
| Web Server & WAS (0) | 2023.07.26 |