본문 바로가기
허브 살리기 프로젝트

Spring 환경에서 외부 요청시 받아오는 데이터의 종류는 어떻게 확인 될 까?

by jay-choe 2024. 3. 10.

Spring 환경으로 개발하다보면 추상화가 너무 잘 되어 있어서 쉽게 개발을 하다가 이슈가 있으면 곤란한 경우가 있다.

 

이전에 공부를 했었을 때 '음.. 요청이 오면 컨버터가 알아서 MIME 타입 확인해서 알맞게 변환해서 처리를 해주네..!' 라고 생각하고 오래 지나서 이 부분까지 신경 쓸 필요가 없었기 때문에 알아서 처리해주는 것이 너무 당연시 되어버렸다.

 

그러다 보니 난감하지만..?? 재미있는 문제를 만났고 해결 과정에서 Spring이 HTTP 요청의 응답을 어떻게 처리하는지 확인을 해봤다.

 

문제상황

Python으로 돌아가는 API 서버에 요청을 하고 응답 값을 받아와서 처리하는 서버를 개발하고 있었다.

받아오는 부분은 OpenFeign을 사용해서 간단하게 받아 오려고 했다.

해당 서버는 JSON 데이터를 응답하고 있었다.

 

하지만 DTO 클래스를 응답 포멧에 맞춰서 만들고 호출 해 봤는데 매핑이 안 되는 것이다.

그동안 개발은 너무 순탄했었는지 이런 에러를 만나 보지 못했다.

 

에러 내용은 'content type [application/octet-stream]'의 converter가 없다는 것인데

Python API에서는 content-type을 제공해주는 부분이 없었다.

 

간략하게 Feign + WireMock 코드로 해당 상황을 재현해봤다.

package com.jay.playground

import com.github.tomakehurst.wiremock.client.WireMock.*
import com.jay.playground.client.TestClient
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock
import org.springframework.test.context.TestPropertySource

@SpringBootTest
@AutoConfigureWireMock(port = 0)
@TestPropertySource(properties = ["client.test.url = http://localhost:\${wiremock.server.port}"])
class PlaygroundApplicationTests(
    @Autowired
    val client: TestClient
) {

    @Test
    fun server_returns_invalid_header() {

        stubFor(
            get(urlEqualTo("/"))
                .willReturn(
                    aResponse()
                        .withBody("{\"element\": \"Hello, Mock\"}")
                )
        )
        print(client.fetch())
    }
}

 

응답은 간단히 element라는 필드가 있는 객체이고 서버에서 받아오는 데이터를 element라는 필드에 매핑을 하려고 했다.

응답 헤더는 당연히 length 같은 부분 밖에 없었고 MIME 타입을 정의하는 내용은 없었다.

 

근데 왜 'octet/stream' 타입을 찾는건지 궁금해서 디버깅 해봤다.

 

 

먼저 Response에서 데이터를 가져 올 때 HttpMessageConverterExtracter라는 클래스에서

getContentType을 통해서 MIME Type을 가져온다.

 

getContentType 에서는 응답 헤더에서 Content-Type 헤더의 내용을 가져오게 되는데 이 헤더가 없으면 위 코드와 같이 'octet-stream'을 사용하게 된다.

 

그래서 헤더를 명시 해주지 않으면 'octet-stream' 헤더를 기준으로 converter를 찾게 되었고, 이 결과 해당 converter가 존재하지 않아서 발생한 에러였다.

 

더 나아가서 그럼 content-type이나 CONTENT_TYPE 같은 대소문자가 섞인 헤더를 넣으면 어떻게 되는지 궁금해서 문자열 비교하는 부분을 찾아봤는데 코드를 파다보니 재미있는 부분이 나왔다.

 

먼저 getFirst 라는 함수를 보면 Content-Type 헤더가 여러개 있어도(동일한 헤더명) 제일 처음 Content-Type 헤더를

사용하는 것을 볼 수 있다.

 

추가적으로 해당 헤더명은 대,소문자 구별을 안하고 있는 것도 확인 할 수 있었다.

'허브 살리기 프로젝트' 카테고리의 다른 글

Spring Boot Warm Up  (0) 2024.04.17
Feign Client Connection Pool  (1) 2024.03.25
Server Side Rendering  (0) 2024.03.03
Image Resizing  (0) 2024.02.26
MySQL UTF8MB4  (0) 2024.02.19