Spring Servlet Web 5.1.3 常用过滤器 : HiddenHttpMethodFilter

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/andy_zhang2007/article/details/86024250

概述

该过滤器的作用是读取POST表单中表示客户端真正想用的HTTP method的隐藏字段(缺省情况下是_method),将其值设置到请求的method属性,也就是随后通过HttpServletRequest#getMethod()获取的值是POST表单中_method字段的值,而不再是POST

之所以会有这种操作,原因是浏览器通常只支持GET,POST,所以一些javascript库,比如Prototype,就采用该方法传递一些真正想用的HTTP method,比如DELETE,PUTPATCH(实际上也最多支持这三种HTTP method)。

缺省情况下,POST表单中表示客户真正想用的HTTP method的字段名称为_method,但实际上也可以是其他名称,该过滤器也缺省使用此名称。但如果用了其他值,可以通过setMethodParam(String)告知该过滤器。

注意,文件上传总是使用POST,并且相应的过滤器MultipartFilter处理会检查POST请求的主体(body)参数,所以该过滤器HiddenHttpMethodFilter必须在文件上传处理过滤器(针对multipart)之后被调用。

该过滤器继承自OncePerRequestFilter,也就是说,它在整个请求处理过程中最多只会被应用一次。

Springboot 提供了一个OrderedHiddenHttpMethodFilter继承自HiddenHttpMethodFilter应用在基于SpringbootServlet Web应用中。OrderedHiddenHttpMethodFilterHiddenHttpMethodFilter的功能上增加了接口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;
		}
	}

}

猜你喜欢

转载自blog.csdn.net/andy_zhang2007/article/details/86024250