相信在使用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請求類似數據封裝層對象這一點操作。
