Fork me on GitHub

通过 Ajax 发送 PUT、DELETE 请求的两种实现方式

一、普通请求方法发送 PUT 请求

     1. 如果不用 ajax 发送 PUT,我们可以通过设置一个隐藏域设置 _method 的值,如下:

1
2
3
4
5
6
7
<form action="/emps" method="post">
    <input type="hidden" name="_method" value="PUT">
    <input type="text" name="username">
    <input type="password" name="password">
            <input type="submit"/>
</form>

  2. 控制层:

1
2
3
4
5
@RequestMapping(value="/emps", method=RequestMethod.PUT)
public String updateEmp(Employee employee) {
    System.out.println(employee);
    return "redirect:success.jsp";
}

  注意:这里如果采用请求转发的方式即 return "success.jsp",将会出现以下问题:(Tomcat 7.0 版本不会出现这个问题)
                 SpringMVC HTTP Status 405 - JSPs only permit GET POST or HEAD
       采用重定向的方式可以避免这个问题。


       3. 这种方式发送 PUT 请求,还需在 web.xml 中配置一个 HiddenHttpMethodFilter 过滤器(如果使用Spring Boot 则会自动配置)

1
2
3
4
5
6
7
8
<filter>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

  

原理/问题:为什么要设置 _method 参数?
        浏览器 form 表单只支持 GET 与 POST 请求,而DELETE、PUT 等 method 并不支持,Spring3.0 添加了一个过滤器,可以将这些请求转换为标准的 http 方法,使得支持 GET、POST、PUT 与 DELETE 请求。
         首先看到 HiddenHttpMethodFilter 过滤器的源码:
        doFilterInternal方法能根据 _method 把 post 请求转化为标准的Http方法,即GET,、POST、 HEAD、OPTIONS、PUT、DELETE、TRACE

二、通过 ajax 发送 DELETE 请求(需要带_method参数)

       这种实现方式跟第一种的原理是一样的,同样是利用 _method 参数对 request 请求进行转换,所以这种方式同样需要配置HiddenHttpMethodFilter 过滤器。
       以下以删除员工为例子(传递员工编号empId):
1
2
3
4
5
6
7
8
9
10
11
12
/* 删除员工 */
function deleteEmp(empId){
    $.ajax({
        url : "emps",
        data : {_method : "DELETE", empId : empId},
        type : "POST",
        success : function(result){    
 
        }
    })
}
            

          发送表单 ajax 请求:

1
2
3
4
5
6
7
8
9
10
11
$("#updateBtn").click(function(){
            $.ajax({
                url : "emps",
                data : $("#updateEmpFormNode").serialize()+"&_method=put",
                type : "post",
                success : function(result){
                    alert(result);
                }
            }) 
 
        })

  

三、直接指定 ajax 请求中的 type 为 put/delete(不带 _method 参数)

         1. 把上述第二点的表单更新改写为如下:

1
2
3
4
5
6
7
8
9
10
11
$("#updateBtn").click(function(){
            $.ajax({
                url : "emps",
                data : $("#updateEmpFormNode").serialize(),
                type : "PUT",
                success : function(result){
                    alert(result);
                }
            })     
 
        })

    出错:

 原因:
       这问题是由于 Tomcat 本身引起的,导致这个问题是因为 SpringMVC 绑定 POJO 对象时获取不到数据,然后执行更新语句时 sql 语句出错导致的。由于 POJO 的数据都为空,所以被执行的更新语句可能会为 update emp set where empId = ?,反正被执行更新语句肯定是有错的。想要知道为什么获取不到数据,下面首先先了解一下 Tomcat 如何封装数据以及SpringMVC如何绑定数据
       1.1 Tomcat 封装表单数据和 SpringMVC 绑定 POJO 对象数据时的流程如下:
                ① Tomcat 首先会将请求体中的数据,封装一个map。
                ② request.getParameter("empName") 就会从这个map中取值。
                ③ SpringMVC封装POJO对象的时候,通过 request.getParamter("empName"); 获取一个字段的值,然后赋值到      POJO 中属性名为 empName 的属性。如:
                           String temp = (String)request.getParamter("empName");
                           Employee emp = new Employee();
                           emp.setEmpName(temp);
        1.2 由于 Ajax 发送的是 PUT 请求,Tomcat一看是PUT不会封装请求体中的数据为map,只有POST形式的请求才封装请求体为map,查看 Tomcat 的源码:
            查找到 protected void parseParameters() 该方法
            protected String parseBodyMethods = "POST";
            if( !getConnector().isParseBodyMethod(getMethod()) ) {
                      success = true;
                      return;
            }
           当 Tomcat 知道是请求不是 POST 请求时,会直接 return,而不会继续往下执行解析封装参数,所以当                        request.getParamter("empName") 从 map 取数据时,由于 empName 参数没有被封装到 map 中,getParmater获取到值为 null。
        2. 解决方法
             2.1 在 web.xml 配置上HttpPutFormContentFilter;
1
2
3
4
5
6
7
8
<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.2  HttpPutFormContentFilter 的作用;将请求体中的数据解析包装成一个map。

            2.3  request被重新包装,request.getParameter()被重写,就会从自己封装的map中取数据

 

四,仍然使用PUT DELETE 请求:传递参数的时候data需要设置为json字符串

  1.仍然使用put和delete请求,直接指定 ajax 请求中的 type 为 put/delete(不带 _method 参数),并且需要传递参数的时候data需要设置为json字符串。(SpringBoot环境中不需要配置任何东西,其他未知)

1
2
3
4
5
6
7
8
9
10
11
var jsonstr = {"id":1,"name":"zsw"};
$.ajax({
    url:"/update",
    type:"PUT",
    contentType:"application/json",//设置请求参数类型为json字符串
    data:JSON.stringify(jsonstr),//将json对象转换成json字符串发送
    dataType:"json",
    success:function(result){
        alert(result);
    },
});

  客户端需要使用@RequestBody标注

1
2
3
4
5
@RequestMapping(value = "update",method = RequestMethod.PUT)
public String update(@RequestBody  Book book){
    System.out.println(book);
    return BookClient.update(book);
}

 我现在正在用的

复制代码
         //不能传表单序列化数据
                var jsonstr = {"id":8,"projectName":"z"};
                $.ajax({
                    url:"/project/update",
                    type:"PUT",
                    contentType:"application/json",//设置请求参数类型为json字符串
                    data:JSON.stringify(jsonstr),//将json对象转换成json字符串发送
                    dataType:"json",
                    success:function(result){
                        alert(result);
                    },
                });    
    
    //对应的controller
    @RequestMapping(value = "update",method = RequestMethod.PUT)
    public Result updateProjectById(@RequestBody Project project){
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
            var data=$("#updateForm").serialize();
            console.log(data);
            $.ajax({
                url:"/project/update",
                type:"POST",
                data : $("#updateForm").serialize()+"&_method=put",
                // data:{_method:"PUT"},
                success:function(result){
                        alert("修改成功");
                }
            })
 
//对应的controller
@RequestMapping(value = "update",method = RequestMethod.PUT)
public Result updateProjectById(Project project){

  

拓展:

  Ajax请求($.ajax()为例)中data属性传参数的形式

参考链接:

  https://blog.csdn.net/Mrs_Yu/article/details/92376069

  https://blog.csdn.net/liuyuanjiang109/article/details/78972644

  

posted @   威威超酷  阅读(6009)  评论(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 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示