SSE 사용기 (3)

Caesars·2024년 10월 25일
1

Springboot

목록 보기
6/6

마지막으로 SSE 사용기를 작성합니다. 실무에 적용하는 과정에 몰랐던 부분이 생겨서 추가했습니다.


EventSource 헤더에 토큰 추가

실시간 알림을 구현하던 중에 서버와 연결하려면 토큰을 헤더에 담아 보내주어야했습니다.

const eventSource = new EventSource(url, 
      {headers: {Authorization : 'Token'}, 
       withCredentials: true});
       
eventSource.onopen = event => {
  console.log("sse connection");
}

하지만 위와 같이 헤더에 토큰을 담아 보내도 request 헤더에는 추가되지 않습니다.
이유를 찾아보니 EventSource는 Same-origin 정책과 CORS(Cross-Origin Resource Sharing)에 따라 동작하는데, Same-origin 정책은 웹 브라우저의 보안을 위해 도메인이나 프로토콜, 포트가 동일한 경우에만 리소스를 공유할 수 있도록 제한합니다. 따라서 다른 도메인으로부터 리소스를 요청할 때는 CORS 정책을 따르게 되므로 EventSource의 헤더에 임의의 토큰을 추가할 수 없게 됩니다.

그래서 XHR 헤더를 수동 주입해주는 솔루션이 있습니다.

해결방법: EventSource Polyfill 사용
EventSource에서 헤더에 토큰을 담아 보내기 위해서는 EventSource Polyfill을 사용해야 한다. EventSource Polyfill은 Fetch API를 사용하여 SSE 요청을 보낼 수 있도록 도와주게 된다. Fetch API는 브라우저의 보안 제약을 우회하고 추가적인 헤더를 포함한 요청을 보낼 수 있게 해주기 때문에 EventSource Polyfill을 사용하면 다음과 같이 헤더에 토큰을 담아 보낼 수 있다:

const eventSource = new EventSourcePolyfill(url, 
      {headers: {Authorization : 'Token'}, 
       withCredentials: true});
       
eventSource.onopen = event => {
  console.log("sse connection");
}

Nginx 사용시 주의할 점

SSE는 지속 연결이 되어 있어야 동작하는데 Nginx에서 지속연결을 닫아버려 제대로 동작하지 않습니다. 따라서 아래와 같이 nginx 설정을 추가해야 제대로 동작합니다.

location =/api/sse/connect {
    proxy_buffering off;            // 버퍼링 기능 비활성. nginx가 was로부터 받은 데이터를 버퍼에 저장하지 않고 클라이언트에 즉시 전송
    proxy_cache off;                // 프록시 캐싱 비활성. nginx가 백엔드 서버로부터 받은 응답을 캐시하지 않음.
    proxy_set_header Connection ''; // 기본적으로 nginx는 connection : close 헤더를 추가하는데 지속적 연결을 위해 connection 헤더를 비우게 함.
    proxy_http_version 1.1;         // HTTP 1.1 을 사용하도록 설정. 1.1은 지속적인 연결을 지원
    chunked_transfer_encoding on;
}

SSE 통신에서 서버는 기본적으로 응답에 Transfer-Encoding:chunked를 사용합니다. SSE는 서버에서 동적으로 생성된 컨텐츠를 스트리밍하기 때문에 본문의 크기를 미리 알 수 없기 때문입니다. Nginx는 서버의 응답을 버퍼에 저장해두었다가 버퍼가 차거나 서버가 응답 데이터를 모두 보내면 클라이언트로 전송하게 됩니다. 문제는 버퍼링 기능을 활성화하면 SSE 통신시 원하는 대로 동작하지 않거나 실시간성이 떨어지게 된다는 것입니다. 따라서 SSE 응답에 대해서는 proxy buffering 설정을 비활성화 해주는 것이 좋습니다. 하지만 Nginx의 설정 파일에서 버퍼링을 비활성화하면 다른 모든 API 응답에 대해서도 버퍼링을 하지 않기 때문에 비효율적 입니다.

다른 api까지 적용되면 안되기 때문에 Nginx location 블록에서 해당 API에 대한 요청에만 설정(=는 일치, ^는 포함)

SSE 연결 시 JSESSIONID 변경

SSE 연결 시 DB Connection 고갈


참조

https://yooneeee.tistory.com/101
https://velog.io/@nanaheui000/event-source-%EA%B4%80%EB%A0%A8-%EB%A9%98%ED%86%A0%EB%8B%98%EC%9D%98-%EB%8B%B5%EB%B3%80
https://gong-check.github.io/dev-blog/BE/%EC%96%B4%EC%8D%B8%EC%98%A4/sse/sse/
https://livelyoneweek.tistory.com/57
https://mentoring-gitlab.gabia.com/mentee/mentee_2023.01/team/weat/gcell-api-server/-/wikis/SSE-%EC%97%B0%EA%B2%B0-%EC%8B%9C-DB-Connection-%EA%B3%A0%EA%B0%88-%EB%AC%B8%EC%A0%9C/diff?version_id=eb08dfffa7f4e3a08590861c21346d78659a1f36

profile
잊기전에 저장

0개의 댓글