[Spring boot] Post 요청, Content-Type

H_rin·2023년 8월 17일

Client에서 POST 방식으로 요청을 보낼 때 발생할 수 있는 오류에 대해서 알아보고자 포스팅

Client에서 요청 시에 HttpMediaTypeNotSupportedException::415 status code Exception이 발생하며 동작하지 않는 이슈가 있다.

보통 org.springframework.web.HttpMediaTypeNotSupportedException 예외

  • RestAPI에서 허용할 수 있는 MediaType이 아니면 에러가 발생한다.

해결 방법은 Content-Type을 잘 맞추면 에러가 생기지 않는다 !


Content-Type

RestAPI의 경우 보통 JSON 타입으로 요청하고, 요청을 받는다.
그래서 당연히 Content-Type으로 application/json를 사용한다고 생각하고 있었고, 이번에 프로젝트 중 오류를 겪게 되어서 자료를 찾게 되었다.

html form 태그를 사용해서 POST 방식으로 요청하거나, jQuery의 ajax 등의 요청을 할 때, Content-Type의 defalut는 application/json이 아니라 application/x-www-form-urlencoded이다.

application/x-www-form-urlencoded

Content-Type: application/x-www-form-urlencoded

name=kim&age=27

//요청 : key1=value1&key2=value2의 형식으로

application/json

Content-Type: application/json

{
	"name":"kim",
    "age":"27"
}

//요청 : 위의 형식으로

Spring에서 POST 요청 받기

보통 RestAPI에서 POST 요청을 받을 때 data가 json 형식으로 body에 들어있다고 가정한다.
따라서 body에서 json 객체를 꺼내어 dto로 받기 위해서 백엔드에서 아래와 같은 코드를 짜게 된다.

@PostMapping(value = "/new")
public String post(@RequestBody Person person){
	
    log.info("person : {}", person);
    
    return person.toString();
}

그런데, 프론트에서 Content-Type을 application/json을 추가해서 보내지 않으면 415 error 가 발생한다.
프론트에서 오류를 해결하는 방법은 Content-Type을 application/json으로 보내는 것

그럼, 우리는 백엔드에서 오류를 해결하는 방법을 알고있어야 한다 !


백엔드에서 해결

@RequestBody@ModelAttribute, @RequestParam 등의 어노테이션을 사용하면
AnnotationMethodHandlerAdapter에 의해 등록된다.

(1) @RequestBody Person

model 객체 앞에 이 어노테이션을 붙이고 JSON 형식의 데이터가 들어오면 해당 json 데이터를 jackson 라이브러리를 사용하여 model 객체로 변환해준다.
-> 당연히 Content-Type은 application/json

@PostMapping(value = "/new")
public String post(@RequestBody Person person){
	
    log.info("person : {}", person);
    
    return person.toString();
}

(2) @RequestBody MultiValueMap<String, String>

MultiValueMap과 함께 어노테이션을 붙이면 application/x-www-form-urlencoded로 정의된 폼 데이터를 주고 받을 때 사용한다.
-> Content-Type은 application/x-www-form-urlencoded

@PostMapping(value = "/new")
public String post(@RequestBody MultiValueMap<String, String> data){
	
    log.info("data : {}", data);
    
    return data.toString();
}

(3) @ModelAttribute Person

model 객체와 함께 @ModelAttribute를 사용하면 key=value를 model로 converting 하게 된다. 앞에 어노테이션을 붙이지 않아도 암묵적으로 사용된다.
-> Content-Type은 application/x-www-form-urlencoded

@PostMapping(value = "/new")
public String post(Person person){
	
    log.info("data : {}", data);
    
    return data.toString();
}

(4) 두 가지 요청 방식

모든 요청을 x-www-urlencoded로 받고 있는 상황에서 json 방식을 추가로 제공해야 하는 상황에 있다면 두 개의 메소드를 만들어주면 된다. 첫번째 메소드는 form-urlencoded 타입, 두번째 메소드는 json 타입을 받는다.

// form-urlencoded 타입
@PostMapping(value = "/new", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public String postFormRequest(Person person){
	
    log.info("form type : person : {}", person);
    
    return person.toString();
}

// json 타입
@PostMapping(value = "/new", consumes = MediaType.APPLICATION_JSON_VALUE)
public String postjSONRequest(@RequestBody Person person){
	
    log.info("json type : person : {}", person);
    
    return person.toString();
}

정리하면,

단순히 POST 방식에서는 @RequestBody를 써야한다거나, 반대로 @ModelAttributeGET 방식에서만 쓸 수 있다 라고만 알고 있다면 이러한 오류를 마주쳤을 때 해결하기 힘들 수 있다.
즉, parameter의 signature 타입과 어노테이션이 AnnotationMethodHandlerAdapter를 통해 알맞는 MessageConverter를 등록한다는 이해가 필요 !

profile
hyerin / 한단계씩 배워가는 백엔드 개발자..(‘•̀ ▽ •́ )φ

0개의 댓글