PATCH METHOD使用

背景

目前广泛使用的HTTP/1.1中定义了八个基本动作①,而PATCH属于扩展动作出现较晚②,很多容器或者库类的API都没有支持。所以我们在处理PATCH方法时常常需要使用一些额外的方法。

语义

用于更新资源的部分内容。例如,更新用户信息中的姓名字段。

和PUT对比

  1. 当资源存在时:
    • PATCH 用于资源的部分内容的更新
    • PUT 用于更新某个资源较完整的内容
  2. 当资源不存在时
    • PATCH 可能会去创建一个新的资源,像是 saveOrUpdate
    • PUT 只对已有资源进行更新操作,所以是 update 操作

实现和支持

  • 支持:

    • Apache HttpComponents HttpClient version 4.2 or later 支持了 PATCH
    • Spring 3.2 开始支持 PATCH 方法,但要选对部署的容器
    • JBoss Netty 支持 PATCH
  • 不支持:

    • 目前 JDK7 的 HttpURLConnection 未实现 PATCH
    • TOMCAT 7 也不行
    • PlayFramework 2 也不支持

在Spring中使用PATCH

背景

PATCH方法默认是以x-www-form-urlencoded③的contentType来发送信息,并且信息内容是放在request的body里。而
Springmvc在解析参数的时候使用的解析器是ServletModelAttributeMethodProcessor,该解析器不支持PATCH,当使用getParameterMap()获取body内容的时候,获取不到信息。

解决办法

1.使用查询字符串传参:

使用POSTMAN模拟客户端发起请求:


查询字符串传参

服务端接收参数:

 /**
  * 更新 (客户端上送部分数据)
  * patch 传递参数的方法:
  *  1) 使用查询字符串
  */
 @RequestMapping(path = "{id}", method = RequestMethod.PATCH)
 @ResponseBody
 public String patch(@PathVariable String id, UserInfo userInfo) {}
2.使用@RequestBody + JSON :

Spring中使用@RequestBody来绑定数据时,使用的是RequestResponseBodyMethodProcessor来解析参数,该解析器可以将json格式的内容装载到pojo里。而@RequestBody只支持以下几种contentType:application/jsonapplication/hal+jsonapplication/pathc+jsonapplication/merge-pathc+json。示例如下:

1)使用PostMan测试

使用POSTMAN模拟客户端发起请求:

  • 设置contentType为application/json
设置contentType
  • 在body中使用JSON传参
JSON数据

服务端接收请求:

/**
 * 更新 (客户端上送部分数据)
 * patch 传递参数的方法:
 *  1) @RequestBody + JSON
 */
@RequestMapping(path = "{id}", method = RequestMethod.PATCH)
@ResponseBody
public String patch(@PathVariable String id, @RequestBody UserInfo userInfo) {}
2)使用ajax作为客户端的代码
$.ajax({
    url: 'http://localhost/v1/users/1',
    type: 'PATCH',
    contextType: 'application/json',
    data: JSON.stringify({
        name: '张三',
        age: '18'
    })
})
3. 使用表单隐藏字段(_method) + HiddenHttpMethodFilter

使用POSTMAN模拟客户端发起请求:

隐藏字段:_method

服务端代码:

  • web.xml中增加filter
<!-- 隐藏方法拦截器 -->
<filter>
    <filter-name>HttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>HttpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
  • controller代码
 /**
  * 更新 (客户端上送部分数据)
  * patch 传递参数的方法:
  *  1) HiddenHttpMethodFilter + 额外字段_method
  */
 @RequestMapping(path = "{id}", method = RequestMethod.PATCH)
 @ResponseBody
 public String patch(@PathVariable String id, UserInfo userInfo) {}
4. 使用HttpPutFormContenrFilter

使用POSTMAN模拟客户端发起请求:

没有_method字段

服务端代码:

  • web.xml中增加filter
    <filter>
        <filter-name>HttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
  • controller代码
 /**
  * 更新 (客户端上送部分数据)
  * patch 传递参数的方法:
  *  1) HttpPutFormContentFilter
  */
 @RequestMapping(path = "{id}", method = RequestMethod.PATCH)
 @ResponseBody
 public String patch(@PathVariable String id, UserInfo userInfo) {}

注:

  • ①: 八个动作分别为: OPTIONS、HEAD、GET、POST、PUT、DELETE、TRACE、CONNECT
  • ②: 2010年3月份才成为正式方法,见“RFC 5789
  • ③:就是application/x-www-from-urlencoded,会将表单内的数据转换为键值对,比如,name=Java&age = 23
  • ④: HiddenHttpMethodFilter和HttpPutFormContenrFilter的区别:

HttpPutFormContenrFilter只能处理PUT和PATCH动作。其内部实现是获取以上两种请求的表单参数后,封装一个新的request包装类:

HiddenHttpMethodFilter

HiddenHttpMethodFilter除了PUT和PATCH还能处理DELETE等动作。但是必须增加一个隐藏参数_method,增加了客户端代码的耦合:

HiddenHttpMethodFilter

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容