๐ŸŒ Spring WebClient ์‘๋‹ต Body ์†Œ๋น„ ๋ฐ ์žฌ์‚ฌ์šฉ ์ด์Šˆ ๋ถ„์„

์กด์Šค๋…ธ์šฐยท2025๋…„ 6์›” 9์ผ
0

๊ธฐํƒ€

๋ชฉ๋ก ๋ณด๊ธฐ
10/10

โœ… ๊ฐœ์š”

Spring WebClient์—์„œ bodyToMono() / bodyToFlux()๋Š” ์‘๋‹ต ๋ณธ๋ฌธ์„ ํ•œ ๋ฒˆ๋งŒ ์†Œ๋น„ํ•  ์ˆ˜ ์žˆ๋Š” 1ํšŒ์„ฑ ์ŠคํŠธ๋ฆผ์ž…๋‹ˆ๋‹ค.


โš ๏ธ ์ฃผ์š” ๋ฌธ์ œ ์š”์•ฝ

  • bodyToMono()๋ฅผ ๋‘ ๋ฒˆ ํ˜ธ์ถœํ•˜๋ฉด โ†’ ๋‘ ๋ฒˆ์งธ๋Š” ๋นˆ ๊ฒฐ๊ณผ ๋˜๋Š” ์˜ค๋ฅ˜
  • ํ•„ํ„ฐ์—์„œ body๋ฅผ ์†Œ๋น„ํ•˜๋ฉด ์ดํ›„ ์ฒด์ธ์—์„œ body๊ฐ€ ๋น„์–ด ์žˆ์Œ
  • ClientResponse๋ฅผ ๋ณต์ œํ•ด๋„ body๋Š” ๊ธฐ๋ณธ๊ฐ’(empty) ์œผ๋กœ ์„ค์ •๋จ

๐Ÿ“Œ ๋ฌธ์ œ ์›์ธ

๋ฆฌ์•กํ‹ฐ๋ธŒ ์ŠคํŠธ๋ฆผ์€ "๋ฐ์ดํ„ฐ๋Š” ํ•œ ๋ฒˆ๋งŒ ๊ตฌ๋… ๊ฐ€๋Šฅ" ์›์น™์„ ๋”ฐ๋ฆ„.
โ†’ ์ด๋ฏธ ํ•œ ๋ฒˆ ์ฝ์€ ์ŠคํŠธ๋ฆผ์€ ๋‹ค๋ฅธ ๊ตฌ๋…์ž์—๊ฒŒ ์žฌ์ „์†ก ๋ถˆ๊ฐ€.


๐Ÿ“Ž ์‚ฌ๋ก€ ์š”์•ฝ

์‚ฌ๋ก€์„ค๋ช…
์‘๋‹ต Body ๋‘ ๋ฒˆ ์ฝ๊ธฐ ์‹œ๋„โŒ ์‹คํŒจ (ํ•œ ๋ฒˆ๋งŒ ์†Œ๋น„ ๊ฐ€๋Šฅ)
ํ•„ํ„ฐ์—์„œ body ๋กœ๊น… ํ›„ ์žฌ์‚ฌ์šฉโŒ body ์†Œ์ง„๋จ
ClientResponse ์žฌ์ƒ์„ฑโš ๏ธ body ๋น„์–ด ์žˆ์Œ (๊ธฐ๋ณธ๊ฐ’: empty)

๐Ÿ’ก ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

โœ”๏ธ 1. ๊ฐ™์€ ์ฒด์ธ ์•ˆ์—์„œ ์ฒ˜๋ฆฌ ํ†ตํ•ฉ

webClient.post()
    .retrieve()
    .bodyToMono(String::class.java)
    .doOnNext { logger.info("์‘๋‹ต ๋ฐ”๋””: $it") }
    .map { objectMapper.readValue<MyDto>(it) }

โœ”๏ธ 2. ๋ณธ๋ฌธ์„ ๋ณ€์ˆ˜์— ์ €์žฅํ•ด์„œ ์žฌ์‚ฌ์šฉ

response.bodyToMono(String::class.java).flatMap { body ->
    val parsed = objectMapper.readValue<MyDto>(body)
    Mono.just(parsed)
}

โœ”๏ธ 3. .cache() ๋˜๋Š” .share() ์‚ฌ์šฉ

val cachedBody = response.bodyToMono(String::class.java).cache()
// ์—ฌ๋Ÿฌ ๊ตฌ๋…์ž์—๊ฒŒ ๋™์ผํ•œ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ ๊ฐ€๋Šฅ

์ฃผ์˜: cache()๋Š” ์—๋Ÿฌ๋„ ์บ์‹œํ•˜๋ฏ€๋กœ ์ฃผ์˜ ํ•„์š”.

โœ”๏ธ 4. ์‘๋‹ต์„ ResponseEntity๋กœ ๋ฐ›๊ธฐ

webClient.post()
    .retrieve()
    .toEntity(String::class.java)
    .flatMap { entity ->
        val body = entity.body
        ...
    }

โœ”๏ธ 5. ํ•„์š” ์—†์„ ๋•Œ๋Š” ๋ช…์‹œ์ ์œผ๋กœ ์†Œ๋น„ ๋˜๋Š” ํ•ด์ œ

// ๋‚ด์šฉ ๋ฌด์‹œํ•˜๊ณ  ์†Œ๋น„
response.bodyToMono(Void::class.java)

// ๋˜๋Š” Spring 5.2+์ผ ๊ฒฝ์šฐ
response.releaseBody()

๐Ÿงช ClientResponse ์žฌ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์‚ฌํ•ญ

response.bodyToMono(String::class.java).flatMap { body ->
    val newResponse = response.mutate()
        .body(Mono.just(body)) // โœ… body ์žฌ์ฃผ์ž… ํ•„์ˆ˜
        .build()
    Mono.just(newResponse)
}

ClientResponse.from() ๋˜๋Š” .mutate()๋กœ ๋ณต์ œํ•  ๋•Œ body๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ empty
๋ฐ˜๋“œ์‹œ .body(...)๋กœ ๋ช…์‹œ์ ์œผ๋กœ ๋‹ค์‹œ ์„ค์ •ํ•ด์ค˜์•ผ ํ•จ


๐Ÿ“ ์š”์•ฝ

  • ์‘๋‹ต Body๋Š” ๋ฐ˜๋“œ์‹œ ํ•œ ๋ฒˆ๋งŒ ์†Œ๋น„ ๊ฐ€๋Šฅ
  • ์žฌ์‚ฌ์šฉํ•˜๋ ค๋ฉด: ์บ์‹ฑํ•˜๊ฑฐ๋‚˜ ๋ฌธ์ž์—ด๋กœ ์ฝ์–ด ๋ณ€์ˆ˜ ์ €์žฅ
  • ํ•„ํ„ฐ์—์„œ ์‘๋‹ต ๋ณธ๋ฌธ ๋กœ๊ทธ๋ฅผ ์ฐ์œผ๋ ค๋ฉด โ†’ ๊ฐ™์€ ์ฒด์ธ์—์„œ .doOnNext ์‚ฌ์šฉ
  • ๋ณธ๋ฌธ์ด ํ•„์š” ์—†๋”๋ผ๋„ ๋ฐ˜๋“œ์‹œ .bodyToMono(Void::class) ํ˜น์€ .releaseBody() ํ˜ธ์ถœ
  • ClientResponse๋ฅผ ๋ณต์ œํ•  ๋• ๋ฐ˜๋“œ์‹œ .body(...)๋กœ ์žฌ์ง€์ •ํ•ด์•ผ ํ•จ

ํ•„์š”ํ•˜๋‹ค๋ฉด ์ด ํ…œํ”Œ๋ฆฟ์„ Notion ๊ณต์œ ์šฉ์œผ๋กœ PDF ๋˜๋Š” ํ…œํ”Œ๋ฆฟ ๋งํฌ๋กœ ์ •๋ฆฌํ•ด์ฃผ๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•˜๋‹ˆ ๋ง์”€ ์ฃผ์„ธ์š”.

profile
์–ด์ œ์˜ ๋‚˜๋ณด๋‹ค ํ•œ๊ฑธ์Œ ๋”

0๊ฐœ์˜ ๋Œ“๊ธ€