본문 바로가기
Springboot

Springboot -SSE ( 로컬에서는 실시간 o / https nginx 서버에서는 실시간 x)

by JunsC 2024. 6. 23.
728x90

스프링부트로 SSE 를 구현해서 소켓 대용으로 효율적인 실시간 스트림 관리를 하고 싶었다. 로컬 환경에서는 SSEemitter keep-alive 시간을 1분간 유지하도록 설정해두고 테스트를 해본 결과 만족스럽게 연동이 잘 되었다.

그리고 실 서버 에 업로드를 하고 테스트를 해본결과 갑자기 실시간 스트림이 연동되지 않았다 !! 두둥..

onCompleteion 만료되었을때만 담아두었던 데이터가 왔다. .. 

심지어 담아둔 데이터가 아니라 초기 더미데이터가 온것이다... 

2일이 걸려 해답을 찾았다...

 

내 생각에는 http, https 의 차이일거라고 생각했다. 거기에 중점을 두어서 구글링과 챗봇 찬스를 쓴 결과 

 

nginx 를 이용한 역방향 프록시로 인해 실시간 스트림이 nginx 버퍼링에 걸리게 되었고 이게 실시간 스트림으로 클라이언트에게 데이터가 바로 가는게 아니라 nginx 버퍼에 담아두고 일정 시간 이후 같이 보내준다는 것이었다 !!!

 

아.... 맞아..... 내가 환경설정 해 둔것이 역방향 프록시라는 부분이였구나...

 

SseEmitter에는 직접 헤더를 설정하는 기능이 없습니다. 그러나, X-Accel-Buffering 헤더를 추가하려면 필터를 통해 설정하거나 직접 HTTP 응답을 제어해야 합니다. X-Accel-Buffering 헤더를 추가하기 위해 Spring 필터를 사용할 수 있습니다.

Spring Filter 사용하여 헤더 추가

Spring에서 필터를 사용하여 모든 HTTP 응답에 X-Accel-Buffering 헤더를 추가할 수 있습니다.

  1. 필터 클래스 생성:
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class SSEFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 초기화 코드 (필요한 경우)
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        if (response instanceof HttpServletResponse) {
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            httpResponse.setHeader("X-Accel-Buffering", "no");
        }
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        // 정리 코드 (필요한 경우)
    }
}
  1. 필터 등록:

Spring Boot 설정 클래스에서 필터를 등록합니다.

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<SSEFilter> sseFilter() {
        FilterRegistrationBean<SSEFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new SSEFilter());
        registrationBean.addUrlPatterns("/connect");
        return registrationBean;
    }
}

이 설정은 /connect 엔드포인트에 대한 모든 응답에 X-Accel-Buffering: no 헤더를 추가합니다. 이렇게 하면 Nginx가 이 엔드포인트에 대한 응답을 버퍼링하지 않게 됩니다.

응답 헤더에 X-Accel-Buffering 직접 추가

필터를 사용하지 않고도, 특정 컨트롤러 메소드 내에서 직접 헤더를 추가할 수 있습니다:

 

@GetMapping(value = "/connect", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public ResponseEntity<SseEmitter> connectRedisSSE() throws IOException {
    SseEmitter emitter = sseService.connect("dummyData").getBody();
    return ResponseEntity.ok()
            .header("X-Accel-Buffering", "no")
            .body(emitter);
}
하지만 SseEmitter와 함께 이 방법을 사용하는 것은 권장되지 않습니다. 왜냐하면, Spring MVC의 SseEmitter는 자체적으로 스트리밍을 관리하기 때문에 응답 헤더를 수정하기 어렵습니다.

요약

Spring 필터를 사용하여 X-Accel-Buffering: no 헤더를 추가하는 것이 가장 깔끔하고 일관된 방법입니다. 이렇게 하면 특정 엔드포인트에 대해 Nginx 버퍼링을 비활성화할 수 있으며, SseEmitter를 사용하는 동안에도 적용됩니다.

 

 

그래서 나는 3번째 방법으로 해결하였다.. 후... 

 

 

'Springboot' 카테고리의 다른 글

vscode_ SpringBoot 프로젝트 만들기  (0) 2024.08.20
Springboot_ [Error] Could not open JPA EntityManager for transaction  (0) 2024.08.12
springboot https 적용기  (0) 2024.06.05
Springboot_ Redis SSE 작업  (0) 2024.06.02
SpringBoot  (0) 2024.02.04
"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."