콘텐츠로 이동

2024 09 20

2024-09-20

SSE (Server-Sent Events)

참고: https://hyuk0309.tistory.com/24 참고: https://velog.io/@alswn9938/SSE%EB%9E%80 참고: https://developer.mozilla.org/ko/docs/Web/API/Server-sent_events/Using_server-sent_events 참고: https://tecoble.techcourse.co.kr/post/2022-10-11-server-sent-events/

  • 개요
    • 서버 -> 클라이언트 실시간으로 데이터를 전송하는 기술
    • 컨셉: HTTP Connection 길게 유지. 서버 -> 클라이언트 데이터 전송
    • 서버 -> 클라 text message를 보내는 브라우저 기반 웹 어플리케이션 기술
      • HTTP의 persistence connections 기반 HTML5 표준 기술
  • vs Polling
    • Short Polling: 주기적으로 API 찔러서 변경사항 확인
      • 장: 준 실시간 | 단: 서버 요청수 너무 많아짐
    • Long Polling: 데이터 변경이 있을 때 까지 기다리다가 응답
      • 장: HTTP 요청 수 감소 | 단: 어쨋든 데이터 변경 시마다, HTTP Connection 맺어야 함
  • SSE
    • HTTP Connection 한번만 맺음
    • 잦은 HTTP 요청 X -> 응답시간 Up, 디바이스 배터리 사용률 Low
  • SSE 원리
    1. HTTP Connection 유지
      • HTTP/1.0 -> header Connection keep-alive
      • HTTP/1.1 -> 트랜잭션 끝나도 연결 유지해서 따로 설정 X
      • HTTP/2.0 -> 하나의 HTTP 커넥션에 HTTP 요청 이뤄져서 설정 X
    2. 그 외 설정
      • HTTP Request
        • Accept Header: text/event-stream
      • HTTP Response
        • Content-Type: text/event-stream
        • Cache-Control: no-store
  • SSE Event format
    • field/value (field 종류: event/data/id/retry)
    • event는 \n\n 으로 구분
    • 인코딩 UTF-8
  • SSE 통신 과정

    1. [Client] SSE Subscribe 요청

      • 서버의 이벤트 구독을 위한 요청 보냄
        > Request Headers
        :authority: bzm-lounge.com
        :method: GET
        :path: /api/notification/1750/sse
        :scheme: https
        Accept: text/event-stream
        
    2. [Server] Subscription에 대한 응답

      • Response 미디어 타입 text/event-stream
    3. [Server] 이벤트 전달
      • 클라이언트에서 Subscribe 하면, 서버는 해당 클라이언트에게 비동기적으로 데이터 전달
      • 서로 다른 이벤트 \n\n 구분, name:value로 구성
        > Response 
        event: count
        data: 1
        
        event: push
        data: {"title":"문의 댓글 업데이트","message":"오호","link":"https://bzm-lounge.com/post/11","serviceType":"BZM"}
        
        event: count
        data: 2
        
        event: push
        data: {"title":"문의 댓글 업데이트","message":"폼미쳤다!","link":"https://bzm-lounge.com/post/10","serviceType":"BZM"}
        
  • [Client] SSE
    // 클라이언트 측은 들어오는 이벤트 처리하는 부분 웹소켓과 거의 유사
    const evtSource = new EventSource("/event/sse", {
        withCredentials: true,
    })
    
    // event 필드가 없는 메시지는 `message` 이벤트로 수신됨. -> 해당 message 이벤트 수신을 위해서는 핸들러를 추가해야 함
    evtSource.onmessage = function (e) {
        const newElement = document.createElement('li');
        const eventList = document.getElementById('list');
        newElement.textContent = "message: " + e.data;
        eventList.appendChild(newElement);
    }
    
    // 사용자 지정 이벤트 수신 -> event 필드를 갖는 서버의 메시지들은 event에 명시된 이름의 이벤트로 수신됨
    evtSource.addEventListener('count', (e) => {
        setCount(e.data);
    })
    
    evtSource.addEventListener('push', (e) => {
        const data = JSON.parse(e.data);
        addPush(data);
    })
    
    evtSource.onerror = (e) => {
      alert("failed!");
    }
    
    // 닫기
    evtSource.close();
    
  • vs Websocket
    • Websocket: 클라 <-> 서버 양방향, 둘이 프로토콜도 다름
    • SSE: 서버 -> 클라 단방향

Redis Pub/Sub