DefaultHandlerExceptionResolver: Resolved ~ : Required request body is missing …

시은·2024년 2월 18일
0
post-thumbnail

오늘도 마주친 에러

기능을 구현하고 프론트에 연결하여 하나씩 해결하던 중, 아래와 같은 에러가 발생하였습니다.

2023-12-01T02:42:01.109+09:00 WARN 90341 --- [io-8081-exec-10] .w.s.m.s.DefaultHandlerExceptionResolver : 
Resolved [org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: 
public org.springframework.http.ResponseEntity<?> wanted.assignment.pmsystem.domain.planner.board.
BoardController.deleteBoard(wanted.assignment.pmsystem.domain.planner.board.dto.requests.DeleteBoardRequest)]

처음보는 에러에 당황스러웠지만, 늘 하던대로 요청이 제대로 갔는지 부터 확인하였습니다.

원래 명세는 DELETE http://localhost:8081/api/boards 에 request body 로 board 의 인덱스를 담아 넘기는 것이였습니다. 하지만 위와 같은 오류가 발생했고, 원인을 찾아보았습니다.


DELETE 에서는 payload body 를 못쓰는걸까? 🤔

DEELTE 명세에는 이상이 없고, request body 에도 문제가 있는데 왜 처리를 못하는건지 처음엔 아래와 같은 오류를 보고 참 당황했습니다.

2023-12-01T02:49:12.598+09:00 WARN 90341 --- [nio-8081-exec-7] .w.s.m.s.DefaultHandlerExceptionResolver : 
Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'DELETE' is not supported]

프론트에서 뭔가 놓친게 있나 싶어 찬찬히 살펴보니 틀린게 전혀 없어보였습니다. 500 에러도 아니고 401 에러니 뭔가 인증문제인가 싶어 살펴봤는데 그 또한 아니였습니다. 이렇게 또한번 맞왜틀에 빠진 김시은… 🫠 

공부하고 보니 이는 프론트에서 DELETE 매핑 시 request body 에 값을 넣어보낼 때 종종 나타나는 오류라고 합니다. 또한 일반적으로는 DELETE 매핑 시 request body 를 사용하지 않는다고 하는데요… 😱 왜 그런지 아래에서 살펴보도록 하겠습니다.

HTTP 스펙에서는 명확하게 DELETE 에 요청 본문의 사용을 금하지 않습니다.

근데 왜 많은 사람들이 쓰지 않는걸까요? DELETE 는 리소스를 제거하는 데 사용되며 이는 일반적으로 리소스 식별자( URL) 를 통해 수행됩니다. 즉, 추가 데이터가 필요하지 않은 경우가 많습니다. 하지만 요청 본문을 포함시키면 이 간결하고 명확한 통신이 복잡해질 수 있습니다. 많은 HTTP 클라이언트, 서버 및 중간자 들은 DELETE 요청의 본문을 예상하지 않기 때문에 이를 올바르게 처리하지 못할 수 있습니다. 따라서 표준화된 접근 방식을 따르는 것이 좋습니다. 하지만 요청 본문이 필요한 경우도 있습니다. 예를 들어 복잡한 삭제 조건이나 추가 메타 데이터를 전송해야 하는 경우에 해당합니다. 하지만 이는 일반적인 관행이 아니며 특정 애플리케이션의 요구에 따라 달라질 수 있습니다.

아니 그럼 이전 프로젝트에서 나 DELETE 어떻게 했더라⁉️

찾아보니 @RequestParam 으로 처리를 했었습니다. 하지만 boardId=1 이렇게 url 에 박히는게 보기싫었던 저는 @PathVariable 로 변경하였습니다.


이번엔 @PathVariable 이 문제 ⁉️

하지만 또다시 나타난 에러… 다시 네트워크를 찬찬히 살펴보고 프론트에는 이상이 없음을 확인하였습니다.

그리고 spring boot 의 service 를 확인해보았는데요, 아래와 같은 오류가 찍혀있는것을 확인할 수 있었습니다. 오류를 찬찬히 읽어보면 파라미터 이름 제대로 지정 하라는 건데요,

java.lang.IllegalArgumentException: Name for argument of type [java.lang.Long] not specified, and parameter name information not found in class file either.
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.updateNamedValueInfo(AbstractNamedValueMethodArgumentResolver.java:183) 
~[spring-web-6.1.1.jar:6.1.1]at

아래와 같이 파라미터명을 명확하게 지정해주면 오류는 해결됩니다. 왜 그럴까요?

@GetMapping(value = "/{boardId}")
public ResponseEntity<?> displayBoardDetail (@PathVariable Long boardId)
@GetMapping(value = "/{boardId}")
public ResponseEntity*<?> displayBoardDetail (@PathVariable*("boardId") Long boardId)

왜 @PathVariable 에 이름을 명시적으로 지정해야 하나요? 🤷🏻‍♀️

@PathVariable 을 사용할 때 "boardId"와 같이 변수의 이름을 명시적으로 지정하면, Spring Framework는 HTTP 요청의 URL 경로에서 해당 변수 이름과 일치하는 부분을 찾아 메소드 파라미터로 전달한다고 합니다. 만약 이렇게 지정하지 않으면 Spring 은 런타임 에서 파라미터의 이름을 알 수 없습니다. 즉, @PathVariable 에 명시적으로 이름을 제공하지 않으면 어떤 URL 경로 변수를 어떤 파라미터로 매핑해야 하는지 결정할 수 없습니다. 파라미터 이름을 명시적으로 작성하면 컴파일 옵션에 관계없이 런타임에 올바른 매핑이 이루어집니다.

profile
창의력 대장이 되기 위한 여정

0개의 댓글