Client에서 POST 방식으로 요청을 보낼 때 발생할 수 있는 오류에 대해서 알아보고자 포스팅
Client에서 요청 시에 HttpMediaTypeNotSupportedException::415 status code Exception이 발생하며 동작하지 않는 이슈가 있다.
org.springframework.web.HttpMediaTypeNotSupportedException 예외해결 방법은 Content-Type을 잘 맞추면 에러가 생기지 않는다 !
RestAPI의 경우 보통 JSON 타입으로 요청하고, 요청을 받는다.
그래서 당연히 Content-Type으로 application/json를 사용한다고 생각하고 있었고, 이번에 프로젝트 중 오류를 겪게 되어서 자료를 찾게 되었다.
html
form태그를 사용해서POST방식으로 요청하거나, jQuery의 ajax 등의 요청을 할 때, Content-Type의 defalut는application/json이 아니라application/x-www-form-urlencoded이다.
Content-Type: application/x-www-form-urlencoded
name=kim&age=27
//요청 : key1=value1&key2=value2의 형식으로
Content-Type: application/json
{
"name":"kim",
"age":"27"
}
//요청 : 위의 형식으로
보통 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에 의해 등록된다.
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();
}
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();
}
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();
}
모든 요청을 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를 써야한다거나, 반대로@ModelAttribute는GET방식에서만 쓸 수 있다 라고만 알고 있다면 이러한 오류를 마주쳤을 때 해결하기 힘들 수 있다.
즉, parameter의 signature 타입과 어노테이션이 AnnotationMethodHandlerAdapter를 통해 알맞는 MessageConverter를 등록한다는 이해가 필요 !