Ajax发送PUT/DELETE请求时出现错误的原因及解决方案

本文讲什么?

大家应该都知道.在HTTP中,规定了很多种请求方式,包括POST,PUT,GET,DELETE等.每一种方式都有这种方式的独特的用处,根据英文名称,我们能够很清楚的知道DELETE方法的作用—-删除请求.而其他的,根据单词并不能准确的知道他们想表达的意思.本文要讲的并不是HTTP协议,主要是分析一下发送Ajax(异步请求)的时候,为什么使用GET和POST方式发送可以接收到数据,而使用DELETE和PUT方法无法发送请求的问题出现原因,当然还是要给出解决办法的.

出现此问题的现象

既然要解决这个问题,那么我们肯定要知道出现这个问题的现象是怎么样子的.
一般情况下,我们使用Rest风格的URI时,也就是使用HTTP协议请求方式的动词,来表示对资源的操作(GET(查询),POST(新增),PUT(修改),DELETE(删除)),常常会出现这个问题.
既然会出现这个令人头痛的问题,那么我们为什么还要用这种Rest风格的URI呢?
REST 是一种软件架构的编码风格,是根据网络应用而去设计和开发的一种可以降低开发复杂度的编码方式,并且可以提高程序的可伸缩性(增减问题)
可以解决的问题:
1) 查询条件多,多种限制条件,分页参数等。
2) 批量操作,解决共性问题
本文中不再详细去解释使用Rest风格的URI的原因,感兴趣的同学可以自己查阅相关的资料.

  • 使用Ajax发送PUT(修改)请求
    我们测试使用的是一个更新方法,利用主键更新员工的信息,使用特定的PUT请求.
    前端代码如下:
$.ajax({
    url: "${pageContext.request.contextPath}/app/" + empId,
    type: "PUT",
    data: $("#app form").serialize(),
    success: function (result) {
        alert(发送成功!);
    }
    error:function(){
        alert("数据发送失败!");
    }
});

后端代码如下:
后端代码非常简单,主要就是接收从前端传回的值,然后利用对应的id更新数据.

/**
 * 员工更新信息
 *
 * @param employee
 * @return
 */
@RequestMapping(value = "/empl/{empId}", method = RequestMethod.PUT)
@ResponseBody
public Message updateEmployee(Employee employee) {
    System.out.println(employee);
    employeeService.updateEmployee(employee);
    return Message.success();
}

出现的情况如下:
warning

可以看到,除了id正常被接收到意外,其他的值全部为null,按道理说SpringMVC会自动把数据封装到对应字段中,form表单中的数据肯定是没有问题的,排除写错字段这一条.那么只能是值传递的时候出现的问题了.
使用浏览器F12查看network时,发现数据已经被封装到了实体信息中,问题究竟是在哪呢?

出现问题的原因

这个问题其实是Tomcat的问题.
实际上,Tomcat把请求的数据(实体信息中的数据)封装成一个Map(键值对形式),request.getParameter(“”)就从map中取值,而SpringMVC会把每个属性的值调用getParameter方法封装,而Tomcat看到是PUT请求则不会封装请求数据到map,只有POST形式的请求才会封装到请求体。
为什么会出现这种情况呢?
实际上这是因为在设计Tomcat的时候就出现的问题.在Tomcat的源代码的Request.java类中,大约是3111行左右的代码,有这样的一段代码.

在下面这个方法中:

有如下代码:

这一段代码的作用是获取连接器,再判断请求的方法是否在规定的方法之中,如果存在,则继续,如果不存在,则直接返回,不进行数据的封装.与我们设置的方法比对的就是代码中的方法,这个方法是POST,所以我们的PUT方法和POST肯定是不一样的,最后只能是返回.于是就出现了上面的情况.

解决方案

这个问题有两种解决方案,第一种比较复杂,第二种比较简单,正常我们肯定是使用第二种的,当然并不排除使用第一种方式的场景.

方案一

  • 配置web.xml文件
<!--使用Rest风格的URI-->
<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>

在发送Ajax请求的时候,使用如下的格式:

$.ajax({
    url: "${pageContext.request.contextPath}/emp/" + id,
    type: "POST",
    data: $("#app form").serialize() +"&_method=PUT",
    success: function (result) {
        alert("操作成功!");
    }
});

可以看到不同的地方,首先配置HiddenHttpMethodFilter,这个类可以把POST转换成对应的_method=?的?号中的内容,从而实现请求.当然每次写Ajax请求的时候,都需要协商method字段,便于解析.

方案二

方案二就比较简单了.只需要一个简单的web.xml的配置.

<!--配置SpringMVC,把PUT或者DELETE请求转换成POST-->
<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>

然后就可以很自然的使用Ajax请求而不需要做任何的处理.

$.ajax({
    url: "${pageContext.request.contextPath}/emp/" + id,
    type: "PUT",
    data: $("#app form").serialize(),
    success: function (result) {
        alert("操作成功!");
    }
});

以上,就是本文的全部内容,谢谢阅读!

结语

好了,这次的文章就到这里了,如果你喜欢我的文章,请关注我,可以点个赞,支持一下我,或者给一些评论,这是对原创作者最大的支持!
也欢迎您关注我的微信公众号:最高权限比特流,可以在后台回复”项目实战”,”java”来获取相关资料进行学习,有任何问题,也可以邮件联系我:roobtyan@outlook.com。感谢您的阅读,再见!

发表评论

电子邮件地址不会被公开。 必填项已用*标注