相信在使用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请求类似数据封装层对象这一点操作。