Spring Boot 2.2.0.RELEASE not mapping thymeleaf put and delete requests

Viewed 1980

After upgrading from Spring Boot 2.1.6.RELEASE to 2.2.0.RELEASE my Thymeleaf based pages are failing when performing puts and deletes on embedded Tomcat. Gets and posts work fine.

I see in Chrome developer tools that the following request is being sent:

Request URL: https://localhost:8443/notifications/1 Request Method: POST

The request body contains both _method="put" and the _csrf token.

Interestingly my integration tests, annotated with @SpringBootTest, are passing.

Spring Boot Actuator shows /notifications/{notificationId} is mapped to PUT.

Switching back to 2.1.6.RELEASE solves the problem.

My Thymeleaf form is defined as follows:

<form id="notificationForm" th:action="@{/notifications/{notificationId}(notificationId=${notification.id})}" th:object="${notification}" th:method="put" class="needs-validation" novalidate autocomplete="off">

My controller method is annotated as follows:

  @PutMapping("/notifications/{notificationId}")
  public String updateNotification(@PathVariable("notificationId") final Long notificationId,
      @Valid @ModelAttribute(name = NOTIFICATION_MODEL_ATTRIBUTE) final NotificationDto notificationDto,
      final BindingResult result, final Model model, final RedirectAttributes attributes) 

When I perform the delete the following stack trace is presented in the console:

org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported
    at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.handleNoMatch(RequestMappingInfoHandlerMapping.java:201)
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod(AbstractHandlerMethodMapping.java:421)
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:367)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.getHandlerInternal(RequestMappingHandlerMapping.java:449)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.getHandlerInternal(RequestMappingHandlerMapping.java:67)
    at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:393)
    at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1234)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1016)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
...

It's as though Spring is not performing the necessary method conversion using _method before resolving the mapping.

Does anyone have any ideas?

1 Answers

It's as though Spring is not performing the necessary method conversion using _method before resolving the mapping.

This is exactly what's happening. This conversion is performed by the HiddenHttpMethodFilter and it is disabled by default in Spring Boot 2.2:

The filter that handles the _method request parameter is now disabled by default as it causes early consumption of a request body if the body may contain parameters. This can be restored by setting either spring.webflux.hiddenmethod.filter.enabled or spring.mvc.hiddenmethod.filter.enabled to true.

You are using Spring MVC so you should set spring.mvc.hiddenmethod.filter.enabled=true.

Related