일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- application.yml
- 포트
- appspec
- 서브쿼리
- 추후정리
- MySQL
- foreignkey
- 외부키
- WeNews
- querydsl
- 적용우선순위
- 커밋메세지수정
- appspec.yml
- 메소드명
- 메세지수정
- EC2
- AuthenticationEntryPoint
- 예약
- docker명령어
- ㅔㄴ션
- 2 > /dev/null
- 검색
- 컨테이너실행
- 참조키
- Query
- 테스트메소드
- subquery
- 네이티브쿼리
- ubuntu
- 테스트
- Today
- Total
제뉴어리의 모든것
@RequestBody, @ResponseBody, 그리고 Content-Type 본문
ajax로 비동기 통신을 하려고 했는데 어떨때는 서버와 클라가 잘 주고 받다가
어떤 경우에는 서버(Controller)에서 데이터를 확인해보니 전부 null인 경우가 발생했다..
도대체 무슨 문제인가... 이것저것 테스트하고 알아본 결과..
서버쪽에서 받는 방식과 클라에서 보내는 방식이 달라서 발생한 문제였다.
우선 일반적인 Spring Boot를 이용하여 클라이언트(웹브라우저)와 통신을 하는 경우
예를들어 클라에서 입력 폼을 이용하여 데이터를 입력받고 submit 버튼을 이용하여 서버로 Post전송한다고 생각해보자.
그리고 그 Post 전송을 받을 Controller쪽 메소드는 아래와같다.
클라에서 보여질 브라우저의 html 소스는 아래와 같다.
controller 메소드에서 받을 준비를 하는 파라미터 객체의 구조는 아래와 같다.
사용자가 세개의 input을 채운 뒤 submit 버튼을 누르면 당연히 controller쪽 메소드의 ReplyDTO에는 데이터들이 변수명에 맞춰 잘 매칭이 되어 들어올 것이다.
이렇게 당연한 사이클이 당연하게 해주는것은
form의 내용을 아무런 설정 없이 submit 한다면
기본적으로 Content-Type을 application/x-www-form-urlencoded 으로 전송을 하므로
Controller의 메소드 또한 해당 값을 잘 받는다. (어떤 원리인지는 더 알아봐야겠다)
그런데 아래와 같이 @RequestBody 어노테이션을 붙이고선
submit 버튼을 눌러 Post 전송을 하면 아래와 같이 415 에러가 발생한다. (물론 위에 메소드는 기이한 구조이긴 하지만 415에러가 가장 우선 문제이다)
즉, 클라는 Content-Type을 application/x-www-form-urlencoded 으로 보냈는데
서버에서는 Json 혹은 xml 형태로 데이터를 받아서 ReplyDTO 자바 객체에 Mapping을 하려고 했기 때문이다.
여기서 잠깐 @RequestBody란?
@RequestBody는 Json이나 XML과 같은 형태의 데이터를 Jackson 등의 MessageConverter를 활용하여 Java Object로 변환한다
그러므로 @RequestBody를 메소드 파라미터에 붙였을땐 클라에서도 Json이나 XML형태로 Content-Type을 보내야지 데이터와 파라미터가 잘 매칭이 되고 그렇지 않을거라면 둘다 기본 x-www-form-urlencoded 으로 주고 받아야 한다는것이다.
그래서 처음에 내가 겪었던 ajax 관련 문제로 돌아가서
아래와 같은 ajax 소스가 있었다.
$(document).on('click', '#btnReplySave', function(){
var replyContent = $('#replContent').val();
var replyReg_id = $('#replyer').val();
var bpard_seq = [[${dto.seq}]];
var paramData = JSON.stringify({"content": replyContent
, "replyer": replyReg_id
, "board_seq": bpard_seq
});
var headers = {"Content-Type" : "application/json"
, "X-HTTP-Method-Override" : "POST"};
$.ajax({
url: "/reply/saveReply"
, headers : headers
, data : paramData
, type : 'POST'
, dataType : 'text'
, success: function(result){
showReplyList();
$('#content').val('');
$('#replyer').val('');
}
, error: function(error){
console.log("에러 : " + error);
}
});
});
btnReplySave 버튼을 누르면 function() 이하의 내용이 실행 되는것이다.
그리고 그렇게 발생되는 Post 전송은 아래와 같은 메소드로 들어오도록 하였는데
replyDTO의 내용들이 모두 null인것이다...
이유는 앞서서 설명한 것과 같이 ajax의 내용을 보면
var paramData = JSON.stringify({"content": replyContent
, "replyer": replyReg_id
, "board_seq": bpard_seq
});
부분에서 Body에 넣을 데이터의 내용을 JSON.stringify 함수를 이용하여 JavaScript 객체를 Json형태의 문자열로 변환하였다.
그리고 header에 Content-Type이 application/json이라고 명시하였다.
var headers = {"Content-Type" : "application/json"
, "X-HTTP-Method-Override" : "POST"};
즉 클라쪽에선
1. 보내는 Body를 Json형태로 변환함.
2. header에 Content-Type이 application/json이라고 명시
로 인해 완전히 Json 형태로 데이터를 보낸것이다.
그런데 서버쪽은 @RequestBody 어노테이션을 붙이지 않고 그냥 ReplyDTO의 변수들과 매칭을 하려니 되지 않았던 것이다. (@RequestBody을 붙이지 않은 서버 상태에서 값을 받고 싶으면 위에 2가지 조건을 모두 해제 시켜야한다)
그러므로 아래와 같이 @RequestBody만 붙여주면 ajax로 보내는 데이터가 정상적으로 매칭이 되어 받아진다.
근데 만약 반대로 @RequestBody를 메소드에 붙여 놓고 클라에서 Content-Type을 application/json이라고 명시하지않는다면?
위에서 말했다시피 서로 보내고 받는 Content-Type이 다르므로 415에러가 발생하고,
Content-Type을 application/json이라고 명시하였지만 JSON.stringify 함수를 사용하지 않아서 정작 데이터의 형태가 json의 형태가 아니라면 400 에러가 발생하여 정상적인 데이터 형태가 아니라고 에러가 날것이다..
결론,
@RequestBody를 이용하여 데이터를 받을 거라면 클라에서도 정확히 Body에 Json형태로 데이터를 포맷하고,
header에도 application/json 임을 명확히 할것.
'기타...' 카테고리의 다른 글
flowchat 무료 작성사이트 (0) | 2021.04.22 |
---|---|
aws 용어 정리 (0) | 2021.04.01 |
html에서 controller로 값을 넘길 때 매개변수에 매칭되는 기준.. (0) | 2021.02.27 |
html, script, thymeleaf 주석 방법 (0) | 2021.02.27 |
Spring boot에 Google Login 연동하기 (0) | 2021.02.18 |