ajax发送PUT请求,使用HttpPutFormContentFilter过滤器接受办法
相信在使用ajax发送put请求时候,肯定遇到过后端数据无法被接受到的405错误。
为什么会遇到这个问题?
1.首先查看Tomcat源码 关于如何将数据封装到Request
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class Request implements HttpServletRequest {} //可以看出就像书中所说一样 Request实现了HttpServletRequest接口 /** * Parse request parameters. */ protected void parseParameters() { if ( !getConnector().isParseBodyMethod(getMethod()) ) { success = true ; return ; } } //受保护的parseParameters()方法 //将数据封装到parameters中去 |
然后查看isParseBodyMethod()方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | 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请求中的数据进行封装
1 2 3 4 5 6 7 8 9 | <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的基本原理是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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请求类似数据封装层对象这一点操作。
恐惧源于无知,代码改变世界
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义