블로그 프로젝트를 하던 와중 타임리프로 이루어진 회원가입페이지에서의 POST(회원가입) 폼 요청을 컨트롤러에서 @RequestBoby
가 붙은 객체에 바인딩 되지 않는 문제가 발생했다.
무엇때문에 발생했고, 어떻게 해결했는지 기록해보자
<form th:action="@{/user}" method="POST">
<!-- 토큰을 추가하여 CSRF 공격 방지 -->
<input type="hidden" th:name="${_csrf?.parameterName}" th:value="${_csrf?.token}" />
<div class="mb-3">
<label class="form-label text-white">Email address</label>
<input type="email" class="form-control" name="email">
</div>
<div class="mb-3">
<label class="form-label text-white">Password</label>
<input type="password" class="form-control" name="password">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
@Controller
@RequiredArgsConstructor
public class UserApiController {
// ...
@PostMapping("/user")
public String signup(@RequestBody AddUserRequest request) {
userService.save(request);
return "redirect:/login";
}
// ...
}
나의 목적은 프론트쪽에서 회원가입폼 데이터를 POST로 보내고 요청을 AddUserRequest
에 매핑시켜 저장하는 것이였는데
프론트로부터 백으로 통신요청을 하면 자꾸 에러를 뱉어내는게 아닌가?!
열심히 구글링한 결과
<from>
태그를 사용해 POST방식으로 요청하거나, JQuery, Ajax 요청을 할 때에는
Content-Type 가 'application/json' 이 아니라 'application/x-www-from-urlencoded' 이다.
위 내용을 토대로 접근해 해결해 보았다.
POST / HTTP/1.1
Host: localhost
Content-Type: application/x-www-from-urlencoded
email=test@gmail.com&password=test
POST / HTTP/1.1
Host: localhost
Content-Type: application/json
{
"email": "test@gmail.com",
"password": "test"
}
위 코드블럭에 보이다시피 application/x-from-urlencoded
타입으로 요청을 보내면 key=value
형태로 요청이가고
application/json
타입으로 요청을 보내면 json
형태로 요청이 간다.
자. 그럼 백엔드에서는 어떻게 받아줘야 할까?
@RequestBody
Content-Type: application/json
인 경우 백엔드 컨트롤러 안 핸들러의 매개변수에 (@RequestBody 타입 매핑할 객체) 를 이용하면 잘 매핑 된다.
@RequestParam
Content-Type: application/x-from-urlencoded
인 경우 백엔드 컨트롤러 안 핸들러의 매개변수에 (@RequestParam 타입 매핑할 객체, @RequestParam ... ) 를 이용해
각각의 파라미터를 매핑시켜 사용한다.