[Spring] @RequestBody vs. @RequestParam

Kim Hyen Su·2024년 10월 29일
0

Spring

목록 보기
13/13
post-thumbnail

개요

코드 리뷰 진행 중 토큰 재발급 요청 API에서 리프레쉬 토큰을 RequestParam으로 전달하도록 정의된 코드를 보고서 "리프레쉬 토큰을 왜 RequestParam에 담아서 전달할까?" 라는 의문이 들었다. 개인적인 생각으로 RequestBody에 담아서 전달해야 더 안전한게 아닐까 라는 의구심이 들었다.

이에 요청 데이터를 추출 시 어떤 데이터를 어떤 방식으로 가져와야 하는지에 대한 정리가 필요하다고 느껴, 해당 포스팅을 작성한다.

참고 포스팅

보안성에 대한 이야기

우선, 리프레쉬 토큰은 URL에 노출되더라도 크게 상관이 없다. 만약, 회원의 민감정보가 담겨있는 토큰인 경우에는 다를 수 있지만, 현재 프로젝트 팀 내에서 리프레쉬 토큰에는 회원을 구분할 수 있는 값 정도만 담겨있다. 따라서, 리프레쉬 토큰을 굳이 바디에 담지 않아도 된다.

그렇다면, @RequestBody와 @RequestParam을 어떻게 구분하여 사용해야 할까?

요청 데이터를 가져오는 방식의 차이

@RequestBody와 @RequestParam 어노테이션 모두 Spring MVC Controller 내에서 HTTP 요청 내 데이터를 가져오기 위해서 사용된다는 공통점이 있다.

그러나 이 두 어노테이션의 목적은 약간 다르다.

@RequestBody 는 HTTP 요청 바디에 담긴 데이터를 추출하기 위해서 사용된다. 주로, JSON 또는 XML 형식의 데이터를 Java 객체 형태로 역직렬화 할 때 사용된다.


@RequestParam 는 각각의 파라미터 값을 추출하기 위해서 사용된다. 주로, 요청 URL 또는 제출된 form 데이터 내 데이터를 추출하기 위해 사용된다.

즉, 요청 헤더의 Content-Type 에 따라서 다른 어노테이션이 사용된다.

  • @RequestParam : application/x-www-form-urlencoded
  • @RequestBody : application/json
  • @RequestPart : multiprat/form-data

Content-Type에 따라 다른 처리

form 데이터

일반적으로 form 데이터는 content-type이 application/x-www-form-urlencoded 로 전달된다. 즉, URL에 쿼리 스트링으로 전달이 된다. 하지만, @RequestBody로 받지 못하는 것은 아니다. 대신에 다음과 같은 결과가 출력된다.

/** 
 * POST 
 * content-type:application/x-www-form-urlencoded
 * /test?name=kim
 */ 

@RestController
public class TestController {

	@PostMapping("/test")
	public ResponseEntity<?> test(@RequestBody String request) {
		System.out.println("출력 결과 : " + request);
		return ResponseEntity.ok().build();
	}
}

// 출력 결과 : name=kim

이는 name 이라는 변수로 사용하기 위해서는 별도의 매핑과정이 추가로 필요하다.

그렇다면, 이를 @RequestParam으로 전달 받아보겠다.

/** 
 * POST 
 * content-type:application/x-www-form-urlencoded
 * /test?name=kim
 */ 

@RestController
public class TestController {

	@PostMapping("/test")
	public ResponseEntity<?> test(@RequestParam String name) {
		System.out.println("출력 결과 : " + name);
		return ResponseEntity.ok().build();
	}
}

// 출력 결과 : kim

위처럼 URL에 쿼리 스트링으로 명시된 키 값을 기준으로 매개변수에 자동 매핑하여 요청을 추출한다. 즉, 파라미터로 전달된 값을 name이라는 변수에 자동 할당되어 사용이 용이하다.

Json 형식

/** 
 * POST 
 * content-type:application/json
 * /test
 * { name : kim }
 */ 

@RestController
public class TestController {

	@PostMapping("/test")
	public ResponseEntity<?> test(@RequestParam String name) {
		System.out.println("출력 결과 : " + name);
		return ResponseEntity.ok().build();
	}
}

// MissingServletRequestParameterException: Required String parameter 'name' is not present

위와 같이 컨트롤러 구현 후 데이터 전송 시 위와 같이 오류가 발생한다.
이는 name 파라미터를 읽지 못하여 발생하는 오류로, @RequestParam은 URL 내에 있는 데이터만 처리가 가능하기 때문에, 요청 바디에 담겨 넘어오는 json 데이터는 읽어내지 못하는 것이다.

/** 
 * POST 
 * content-type:application/json
 * /test
 * { name : kim }
 */ 

@RestController
public class TestController {

	@PostMapping("/test")
	public ResponseEntity<?> test(@RequestBody Person person) {
		System.out.println("출력 결과 : " + person);
		return ResponseEntity.ok().build();
	}
}

// 출력 결과 : Person{name='kim'}

위처럼 @RequestBody로 받게 될 경우에, json 데이터를 자동으로 자바 객체로 매핑을 해주게 된다.

결론

  • @RequestParam : URL 상에서 사용되는 데이터를 추출할 때 사용되며, 이는 민감정보가 아닌 경우 사용할 수 있다.
  • @RequestBody : json 데이터를 객체로 자동 매핑할 경우 사용되며, 이는 민감정보와 같이 URL에 쉽게 노출되지 않아야 할 경우 사용할 수 있다.
profile
백엔드 서버 엔지니어

0개의 댓글