日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

【SpringBoot的坑】Restful请求报错Request method 'POST' not supported,HiddenHttpMethodFilter无法将POST转换为PUT原因分析

發(fā)布時(shí)間:2024/2/28 javascript 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【SpringBoot的坑】Restful请求报错Request method 'POST' not supported,HiddenHttpMethodFilter无法将POST转换为PUT原因分析 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

直接上結(jié)論:

因?yàn)?SpringBoot 版本原因,在我目前使用的 2.2.4 版本中,需要在springapplication.xml文件中 添加配置:

spring.mvc.hiddenmethod.filter.enabled = true

什么是 REST

Restful 目的只是讓 url 看起來更簡(jiǎn)潔實(shí)用,是資源狀態(tài)的一種表達(dá)。


Restful 的使用

由于 H5 的 form 表單僅支持 POST 和 GET 兩種請(qǐng)求,實(shí)現(xiàn) restfulAPI 還需要 PUT 和 DELETE ,所以需要使用 HiddenHttpMethodFilter 組件在發(fā)送HTTP請(qǐng)求時(shí)對(duì)請(qǐng)求類型進(jìn)行偽裝。

<!--需要區(qū)分是員工修改還是添加;表單頁面只支持get和post方式,所以不能直接把method="post"改成method="put"--> <form th:action="@{/emp}" method="post"><!--發(fā)送 put請(qǐng)求修改員工數(shù)據(jù)--><!--1、SpringMVC中配置HiddenHttpMethodFilter;(SpringBoot自動(dòng)配置好的,所用是將請(qǐng)求轉(zhuǎn)成我們指定的方式)2、頁面創(chuàng)建一個(gè)post表單3、創(chuàng)建一個(gè)input項(xiàng),name="_method";值就是我們指定的請(qǐng)求方式--><!--這是一個(gè)添加、修改二合一頁面,判斷如果是修改,才顯示這個(gè)input標(biāo)簽 --><!--此隱藏域可以被HiddenHttpMethodFilter所處理,然后分發(fā)到不同的HttpMethod的處理器上--><input type="hidden" name="_method" value="put" th:if="${emp!=null}"/>

前端處理
表單頁面只支持get和post方式,所以頁面創(chuàng)建一個(gè)post表單,表單里面創(chuàng)建一個(gè)input項(xiàng),name="_method",值就是我們指定的請(qǐng)求方式。

后臺(tái)處理
后臺(tái)需要用 HiddenHttpMethodFilter,該組件 SpringBoot 已經(jīng)自動(dòng)配置好,無需再 @Bean 組件


錯(cuò)誤分析

今天在學(xué) SpringBoot 的時(shí)候遇到了由于 starter 版本 1 和 2 不同造成的小坑:

后臺(tái)總是無法映射到 Controller 里對(duì)應(yīng)的 PUT 請(qǐng)求,報(bào)錯(cuò):

后臺(tái)報(bào)錯(cuò):Request method ‘POST’ not supported

EmployeeController.java 的部分代碼如下:

/*** 員工刪除* @param id* @return*/@DeleteMapping("/emp/{id}") // 處理 delete 請(qǐng)求public String deleteEmployee(@PathVariable("id") Integer id) {System.out.println("刪除員工id:" + id);employeeDao.delete(id);return "redirect:/emps";}

一開始以為是前端頁面的問題,F12 看了一下 HTTP 請(qǐng)求頭和表單提交信息:

看上圖中顯示的請(qǐng)求信息,提交的是post請(qǐng)求,表單中的_method屬性值為delete,沒啥問題

然后去瞄了眼 webmvc 的自動(dòng)配置類 WebFluxAutoConfiguration:
(路徑是org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java)

@Bean @ConditionalOnMissingBean(HiddenHttpMethodFilter.class) @ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false) public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {return new OrderedHiddenHttpMethodFilter(); }

?發(fā)現(xiàn)較先前版本多了@ConditionalOnProperty的注解,也就是條件引入。查看括號(hào)內(nèi)的內(nèi)容可以知道,這個(gè)組件是否加入容器決定于這個(gè)屬性,再看下SpringBoot配置的metadata元數(shù)據(jù)對(duì)這個(gè)property的說明:
(路徑是C:\Users\Bug\.m2\repository\org\springframework\boot\spring-boot-autoconfigure\2.2.4.RELEASE\spring-boot-autoconfigure-2.2.4.RELEASE.jar!\META-INF\spring-configuration-metadata.json)

{"name": "spring.mvc.hiddenmethod.filter.enabled","type": "java.lang.Boolean","description": "Whether to enable Spring's HiddenHttpMethodFilter.","defaultValue": false },

可以知道 SpringBoot 僅在spring.mvc.hiddenmethod.filter.enabled這個(gè) property 的值為 true 時(shí)才會(huì)引入這個(gè)組件,但 SpringBoot 默認(rèn)該屬性值為 false ,所以該版本這個(gè)組件是默認(rèn)沒有加入容器的。

所以我們只需在配置文件里加上這一句:spring.mvc.hiddenmethod.filter.enabled = true 即可。


附:Spring 的 HiddenHttpMethodFilter 源碼

/** Copyright 2002-2018 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** https://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package org.springframework.web.filter;import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale;import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse;import org.springframework.http.HttpMethod; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.util.WebUtils;/*** {@link javax.servlet.Filter} that converts posted method parameters into HTTP methods,* retrievable via {@link HttpServletRequest#getMethod()}. Since browsers currently only* support GET and POST, a common technique - used by the Prototype library, for instance -* is to use a normal POST with an additional hidden form field ({@code _method})* to pass the "real" HTTP method along. This filter reads that parameter and changes* the {@link HttpServletRequestWrapper#getMethod()} return value accordingly.* Only {@code "PUT"}, {@code "DELETE"} and {@code "PATCH"} HTTP methods are allowed.** <p>The name of the request parameter defaults to {@code _method}, but can be* adapted via the {@link #setMethodParam(String) methodParam} property.** <p><b>NOTE: This filter needs to run after multipart processing in case of a multipart* POST request, due to its inherent need for checking a POST body parameter.</b>* So typically, put a Spring {@link org.springframework.web.multipart.support.MultipartFilter}* <i>before</i> this HiddenHttpMethodFilter in your {@code web.xml} filter chain.** @author Arjen Poutsma* @author Juergen Hoeller* @since 3.0*/ public class HiddenHttpMethodFilter extends OncePerRequestFilter {private static final List<String> ALLOWED_METHODS =Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(),HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));/** Default method parameter: {@code _method}. */public static final String DEFAULT_METHOD_PARAM = "_method";private String methodParam = DEFAULT_METHOD_PARAM;/*** Set the parameter name to look for HTTP methods.* @see #DEFAULT_METHOD_PARAM*/public void setMethodParam(String methodParam) {Assert.hasText(methodParam, "'methodParam' must not be empty");this.methodParam = methodParam;}@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {HttpServletRequest requestToUse = request;if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {String paramValue = request.getParameter(this.methodParam);if (StringUtils.hasLength(paramValue)) {String method = paramValue.toUpperCase(Locale.ENGLISH);if (ALLOWED_METHODS.contains(method)) {requestToUse = new HttpMethodRequestWrapper(request, method);}}}filterChain.doFilter(requestToUse, response);}/*** Simple {@link HttpServletRequest} wrapper that returns the supplied method for* {@link HttpServletRequest#getMethod()}.*/private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {private final String method;public HttpMethodRequestWrapper(HttpServletRequest request, String method) {super(request);this.method = method;}@Overridepublic String getMethod() {return this.method;}}}

總結(jié)

以上是生活随笔為你收集整理的【SpringBoot的坑】Restful请求报错Request method 'POST' not supported,HiddenHttpMethodFilter无法将POST转换为PUT原因分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。