405 METHOD_NOT_ALLOWED
in Debugging
HTML form 태그 사용시 발생한 문제
🚨 문제
Spring WebFlux
를 학습하다 마주친 문제이다.
에러 메시지 그대로 해당 URI는 GET 방식의 HTTP 메서드를 지원하지 않는다는 의미이다.
Sun Jan 09 18:19:47 KST 2022
[d6491d4c-11, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:57273] There was an unexpected error (type=Method Not Allowed, status=405).
Request method 'GET' not supported
org.springframework.web.server.MethodNotAllowedException: 405 METHOD_NOT_ALLOWED "Request method 'GET' not supported"
at org.springframework.web.reactive.result.method.RequestMappingInfoHandlerMapping.handleNoMatch(RequestMappingInfoHandlerMapping.java:181)
Suppressed: The stacktrace has been enhanced by Reactor, refer to additional information below:
Error has been observed at the following site(s):
*__checkpoint ⇢ org.springframework.boot.web.reactive.filter.OrderedHiddenHttpMethodFilter [DefaultWebFilterChain]
*__checkpoint ⇢ HTTP GET "/carts/items/61daa8af245e0001a2670b47" [ExceptionHandlingWebHandler]
Original Stack Trace:
at org.springframework.web.reactive.result.method.RequestMappingInfoHandlerMapping.handleNoMatch(RequestMappingInfoHandlerMapping.java:181)
🚧 원인
HTML의 form
태그는 GET
과 POST
만 지원한다고 한다.
헌데, 나는 form태그에 DELETE 메서드를 사용했고, HTML이 이것을 인식하지 못해 결과적으로 DELETE
가 아닌 GET
으로 요청이 발생했고, 해당 URI로 요청을 받는 컨트롤러는 작성돼있지 않았기 때문에 발생한 문제로 추측된다.
HTML을 만져본지 몇 달 지났더니 아리송하다.
<form method="delete" th:action="@{'/carts/items/'+${item.id}}">
<input type="submit" value="Delete from Cart"/>
</form>
@Controller
@RequiredArgsConstructor
@RequestMapping("/carts")
class CartController {
private final CartManager cartManager;
@GetMapping
public Mono<Rendering> viewCart() {
return cartManager.viewCart();
}
@GetMapping("/items")
public Mono<Rendering> search(
@RequestParam(required = false) String itemName,
@RequestParam boolean useAnd
) {
return cartManager.viewCart(itemName, useAnd);
}
@PostMapping("/items/{itemId}")
public Mono<String> addToCart(@PathVariable String itemId) {
return cartManager.addItemToCart("MyCart", itemId)
.thenReturn("redirect:/carts");
}
// 문제 발생 부분
@DeleteMapping("/items/{itemId}")
public Mono<String> deleteFromCart(@PathVariable String itemId) {
return cartManager.deleteFromCart("MyCart", itemId)
.thenReturn("redirect:/carts");
}
}
✅ 해결
form 태그의 메서드를 POST로 변경해주고, form 태그 안에 하기와 같은 hidden input 태그를 추가한다.
<form method="post" th:action="@{'/carts/items/'+${item.id}}">
<input type="hidden" name="_method" value="delete">
<input type="submit" value="Delete from Cart"/>
</form>
일반적인 HTML을 사용한다면 여기서 끝날 것 같은데, 나는 타임리프(Thymeleaf)
와 웹플럭스(WebFlux)
를 사용하였으므로 하기의 설정을 추가해주었다.
# file: 'application.yaml'
spring:
webflux:
hiddenmethod:
filter:
enabled: true