콘텐츠로 이동
Bluetape4k 문서1.11

WebFlux 요청 컨텍스트와 DataBuffer

최신 안정판 Bluetape4k 1.11.0 릴리스 기준

현재 요청은 Reactor Context에 둔다

섹션 제목: “현재 요청은 Reactor Context에 둔다”

HttpRequestCapturerServerHttpRequest 복제본을 ServerHttpRequest::class.java 키로 Reactor Context에 저장합니다. HttpRequestHolder.getHttpRequest()는 구독 시점의 context를 읽고 값이 없으면 빈 Mono를 반환합니다.

val request = HttpRequestHolder.getHttpRequest().awaitSingleOrNull()
val requestId = request?.headers?.getFirst("X-Request-Id")

ThreadLocal 전역 holder가 아닙니다. filter chain 밖에서 새 publisher를 만들거나 Reactor Context를 잃으면 요청도 조회되지 않습니다. request 전체를 장기간 저장하지 말고 필요한 값만 읽어 domain 호출에 넘깁니다.

HttpRequestCapturer@Component이므로 application scan 범위에 들어와야 합니다. 다른 filter가 context 값을 필요로 한다면 ordering을 명시하고 실제 request pipeline에서 검증합니다.

AbstractRedirectWebFilter는 HTTP redirect 응답을 보내지 않습니다. path가 정확히 일치할 때 ServerWebExchange의 request path를 바꿔 다음 filter로 넘기는 내부 rewrite입니다. query와 나머지 exchange 정보는 유지됩니다.

InputStream, channel, Path, Spring ResourceFlow<DataBuffer>로 바꿀 수 있습니다.

fun download(path: Path, factory: DataBufferFactory): Flow<DataBuffer> =
path.readAsDataBuffer(factory, bufferSize = 16 * 1024)

반환 Flow는 수집할 때 읽기를 시작합니다. 여러 번 수집하면 source를 여러 번 열거나 같은 stream을 재사용하려 할 수 있으므로 source 수명을 확인합니다. 대용량 응답은 join()으로 합치지 말고 streaming을 유지합니다.

takeUntilByteCount는 지정한 누적 byte까지만 전달하고, skipUntilByteCount는 그만큼 건너뜁니다. join(maxByteCount)는 여러 buffer를 하나로 합칩니다.

외부 입력을 무제한 join()하면 heap 또는 direct memory를 소진할 수 있습니다. protocol이나 application limit을 maxByteCount로 명시하고, 초과 시 Spring이 발생시키는 오류를 client에게 어떻게 매핑할지 정합니다.

Netty pooled DataBuffer는 reference count를 갖습니다. retain, touch, release helper는 DataBufferUtils에 위임합니다.

val retained = buffer.retain()
try {
consume(retained)
} finally {
retained.release()
}

소유권을 넘겨받은 쪽만 해제해야 합니다. 이미 framework가 소비·해제하는 buffer를 다시 release하거나, 별도 비동기 작업으로 넘기면서 retain하지 않으면 use-after-release 또는 leak이 생길 수 있습니다. write(OutputStream)과 channel overload는 대상 stream/channel을 자동으로 닫지 않습니다.

오류 응답과 관측에서 Web 경계의 실패를 응답과 telemetry로 표현하는 방법을 설명합니다.