ajax发送PUT请求,使用HttpPutFormContentFilter过滤器接受办法

相信在使用ajax发送put请求时候,肯定遇到过后端数据无法被接受到的405错误。

为什么会遇到这个问题?

1.首先查看Tomcat源码 关于如何将数据封装到Request

public class Request
implements HttpServletRequest {}
//可以看出就像书中所说一样 Request实现了HttpServletRequest接口

/**
     * Parse request parameters.
     */
    protected void parseParameters() {

    if( !getConnector().isParseBodyMethod(getMethod()) ) {
                success = true;
                return;
            }
}
//受保护的parseParameters()方法
//将数据封装到parameters中去  

然后查看isParseBodyMethod()方法

public class Connector extends LifecycleMBeanBase  {
    protected String parseBodyMethods = "POST";
    protected HashSet<String> parseBodyMethodsSet;

@Override
    protected void initInternal() throws LifecycleException {

        super.initInternal();

        // Initialize adapter
        adapter = new CoyoteAdapter(this);
        protocolHandler.setAdapter(adapter);

        // Make sure parseBodyMethodsSet has a default
        if( null == parseBodyMethodsSet ) {
            setParseBodyMethods(getParseBodyMethods());
        }

        if (protocolHandler.isAprRequired() &&
                !AprLifecycleListener.isAprAvailable()) {
            throw new LifecycleException(
                    sm.getString("coyoteConnector.protocolHandlerNoApr",
                            getProtocolHandlerClassName()));
        }

        try {
            protocolHandler.init();
        } catch (Exception e) {
            throw new LifecycleException
            (sm.getString
                    ("coyoteConnector.protocolHandlerInitializationFailed"), e);
        }

        // Initialize mapper listener
        mapperListener.init();
    }

    public void setParseBodyMethods(String methods) {

        HashSet<String> methodSet = new HashSet<String>();

        if( null != methods ) {
            methodSet.addAll(Arrays.asList(methods.split("\\s*,\\s*")));
        }

        if( methodSet.contains("TRACE") ) {
            throw new IllegalArgumentException(sm.getString("coyoteConnector.parseBodyMethodNoTrace"));
        }

        this.parseBodyMethods = methods;
        this.parseBodyMethodsSet = methodSet;

    }
    
   protected boolean isParseBodyMethod(String method) {

        return parseBodyMethodsSet.contains(method);

    }  
        
}public String getParseBodyMethods() {

        return this.parseBodyMethods;

    }

上面源码的内容就是Connector的默认方法是POST,然后其中的如果不是“Post”,数据将无法封装到Parameter中去

那么解决办法是:

可以使用HttpPutFormContentFilter过滤器,将PUT请求的表单内容传输通过过滤器封装到Request对象中去

具体步骤如下

1.通过web.xml配置一个过滤器,将PUT请求中的数据进行封装

        <filter>
		<filter-name>HttpPutFormContentFilter</filter-name>
		<filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
	</filter>
	
	<filter-mapping>
		<filter-name>HttpPutFormContentFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>    

2.HttpPutFormContentFilter的基本原理是

public class HttpPutFormContentFilter extends OncePerRequestFilter{

		if (("PUT".equals(request.getMethod()) || "PATCH".equals(request.getMethod())) && isFormContentType(request)) {
			HttpInputMessage inputMessage = new ServletServerHttpRequest(request) {
				@Override
				public InputStream getBody() throws IOException {
					return request.getInputStream();
				}
			};
			MultiValueMap<String, String> formParameters = formConverter.read(null, inputMessage);
			HttpServletRequest wrapper = new HttpPutFormContentRequestWrapper(request, formParameters);
			filterChain.doFilter(wrapper, response);
		}
		else {
			filterChain.doFilter(request, response);
		}
}

 基本思路是从request中获取request,getInputStream()的流 inputMessage

然后将流中的数据封装到Map中 MultiValueMap 最后将数据重新封装到request对象中去,完成put数据的封装

实现Toncat的Request不满足的PUT请求类似数据封装层对象这一点操作。

 

posted @ 2018-10-28 10:48  coder-zhou  阅读(2657)  评论(0编辑  收藏  举报