概述
该过滤器的作用是读取POST表单中表示客户端真正想用的HTTP method的隐藏字段(缺省情况下是_method),将其值设置到请求的method属性,也就是随后通过HttpServletRequest#getMethod()获取的值是POST表单中_method字段的值,而不再是POST。
之所以会有这种操作,原因是浏览器通常只支持GET,POST,所以一些javascript库,比如Prototype,就采用该方法传递一些真正想用的HTTP method,比如DELETE,PUT和PATCH(实际上也最多支持这三种HTTP method)。
缺省情况下,POST表单中表示客户真正想用的HTTP method的字段名称为_method,但实际上也可以是其他名称,该过滤器也缺省使用此名称。但如果用了其他值,可以通过setMethodParam(String)告知该过滤器。
注意,文件上传总是使用
POST,并且相应的过滤器MultipartFilter处理会检查POST请求的主体(body)参数,所以该过滤器HiddenHttpMethodFilter必须在文件上传处理过滤器(针对multipart)之后被调用。
该过滤器继承自OncePerRequestFilter,也就是说,它在整个请求处理过程中最多只会被应用一次。
Springboot 提供了一个OrderedHiddenHttpMethodFilter继承自HiddenHttpMethodFilter应用在基于Springboot的Servlet Web应用中。OrderedHiddenHttpMethodFilter在HiddenHttpMethodFilter的功能上增加了接口OrderedFilter定义的过滤器顺序,并且缺省使用优先级-10000。在整个Servlet过滤器链中,过滤器的顺序数字越小,表示越先被调用。
源代码分析
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;
public class HiddenHttpMethodFilter extends OncePerRequestFilter {
// 真正支持可替换的HTTP method的集合 :PUT, DELETE, PATCH
private static final List<String> ALLOWED_METHODS =
Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(),
HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));
/** Default method parameter: _method. */
// 从POST FORM中获取真正HTTP method的字段的名称的缺省值:"_method"
public static final String DEFAULT_METHOD_PARAM = "_method";
// 从POST FORM中获取真正HTTP method的字段的名称,缺省使用"_method"
private String methodParam = DEFAULT_METHOD_PARAM;
/**
* Set the parameter name to look for HTTP methods.
* 设置从POST FORM中获取真正HTTP method的字段的名称
* @see #DEFAULT_METHOD_PARAM
*/
public void setMethodParam(String methodParam) {
Assert.hasText(methodParam, "'methodParam' must not be empty");
this.methodParam = methodParam;
}
@Override
protected 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) {
// 如果当前 request.getMethod()是POST并且尚无错误,则获取POST FORM的_method参数,
// 如果它存在并且是允许的HTTP method之一,则将当前请求进行包装,使其在调用getMethod()
// 时返回请求参数_method的值
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);
}
// 对请求做封装,使其使用方法 getMethod()返回指定的值
private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
private final String method;
public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
super(request);
this.method = method;
}
@Override
public String getMethod() {
return this.method;
}
}
}

本文深入解析了HiddenHttpMethodFilter的工作原理,这是一种在Spring框架中用于处理HTTP方法的过滤器。文章详细介绍了如何通过POST表单中的_method参数来改变请求的实际HTTP方法,如PUT、DELETE或PATCH,以及该过滤器在文件上传和基于SpringBoot应用中的作用。
1104

被折叠的 条评论
为什么被折叠?



