Backend/Spring+Boot

Ajax와 @RequestBody, @ResponseBody

findmypiece 2021. 8. 4. 23:53
728x90

너무 단순한 주제지만 프로젝트를 분석하다보면 잘못 사용된 경우도 있고 나도 제대로 알지 못하고 사용했던 부분이 있어 정리해놓는다.

우선 아래와 같은 Controller 메소드가 있다고 가정해보자. 해당 메소드에서는 @RequestBody 에 의해 request body 에 있는 json 문자열을 Map<String, Object> 타입 payload로 역직렬화 해서 읽어오고 @ResponseBody 에 의해 Map<String, Object> 타입 map 을 json 문자열로 직렬화해서 리턴한다.

@PostMapping("/update") 
@ResponseBody 
public Map update(@RequestBody Map<String, Object> payload) { 
  Map<String, Object> map = new HashMap<>(); 
  map.put("test", "test"); 
  return map; 
}


위 메소드를 호출하기 위한 ajax 구문은 어떻게 작성해야 할까? 우선 잘못된 예부터 알아보자.

$.ajax({ 
  url: '/update', 
  data: { 
    param_1 : '111', 
    param_2 : '222' 
  }, 
  type: 'POST', 
  dataType: 'json', //서버에서 리턴하는 데이터를 무엇으로 인식할지 지정 
  success: function(data) { 
    console.log(data.test); 
  }, 
  error: function() {
    ... 
  } 
});


위와 같이 호출할 경우 서버쪽에 @RequestBody로 지정된 payload에는 아무런 값도 담기지 않게 된다. Ajax에서 data 항목으로 지정한 데이터가 body에 담겨서 전송되어야 하는데 위와 같이 지정하면 url에 queryString으로 포함되어 header에 담겨서 전송되게 된다.

참고로 type이 GET이면 header에 담기고 POST면 body에 담긴다고 생각하는 사람도 있는데 이는 data가 어디에 담기는지에 대해서는 전혀 영향을 주지 않는다.

header, body 중 어디에 담기느냐는 ContentType이 결정하는데 ajax의 ContentType은 기본값이 application/x-www-form-urlencoded 으로 이는 파라미터는 header 포함되게 된다. 만약 body에 담고 싶다면 ContentType을 아래와 같이 application/json 로 지정해줘야 한다.

$.ajax({
  url: '/update',
  contentType: 'application/json',
  data: {
    param_1: '111',
    param_2: '222'
  },
  type: 'POST',
  dataType: 'json', //서버에서리턴하는데이터를무엇으로인식할지지정
  success: function(data){
    console.log(data.test);
  },
  error: function(){
    ...
  }
});


그런데 이렇게 하면 서버에서 또다시 에러가 발생할 것이다. Ajax에서는 ContentType 을 application/json 로 지정해서 body에 json 문자열을 담아서 보낸다고 했고 서버에서는 @RequestBody 에 의해 body에 있는 json문자열을 Map<string, object> 타입으로 역직렬화 하려고 할텐데 정작 body에 들어있는 것은 json 오브젝트이기 때문이다. 이에 아래와 같이 json 오브젝트를 문자열로 변환해서 보내줘야 한다.

$.ajax({
  url: '/update',
  contentType: 'application/json',
  data: JSON.stringify({
    param_1: '111',
    param_2: '222'
  }),
  type: 'POST',
  dataType: 'json', //서버에서리턴하는데이터를무엇으로인식할지지정
  success: function(data){
    console.log(data.test);
  },
  error: function(){
    ...
  }
});


끝으로 잘못된 예를 다루진 않았지만 확실히 해둬야 할 것 같아 @ResponseBody 에 대해서도 추가로 정리해보자면 이는 리턴하는 객체를 json 문자열로 직렬화 해주는 역할을 한다.

해당 응답을 받는 Ajax에서는 해당 문자열을 일일히 파싱할게 아니라면 다시 json 오브젝트 변환해야 "오브젝트명.키값" 으로 데이터를 읽을 수 있다. 그런데 dataType을 json으로 지정해주면 응답받은 문자열이 json포맷일 경우 success 단계에서 자동으로 json 오브젝트로 역직렬화를 해준다.

dataType 의 default 값은 text로 이렇게 되면 역직렬화 단계 없이 json 문자열 그대로 받아오기 때문에 이 경우 success 단계에서 아래와 같이 수동으로 역직렬화해서 사용해야 한다.

success: function(data) { 
  const jsonData = JSON.parse(data); 
  console.log(jsonData.test); 
}

 

https://ksabs.tistory.com/110
728x90

'Backend > Spring+Boot' 카테고리의 다른 글

Feign 파일 전송하기  (0) 2021.08.09
@RequestPart?  (0) 2021.08.05
@RequestParam, @ModelAttribute 생략  (0) 2021.08.04
Thymeleaf 훑어보기  (0) 2021.07.30
의존성 주입시 중복되는 타입에 대한 처리  (0) 2021.07.23