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

 

posted @   coder-zhou  阅读(2658)  评论(0编辑  收藏  举报
编辑推荐:
· .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 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
点击右上角即可分享
微信分享提示