0%

HTTP PUT 与 POST 的区别

在 HTTP 协议支持的方法中,PUT 和 POST 是比较容易混淆的一对。我们来看看在 RESTful API 中应该如何正确使用这两种方法。

从语义的角度来说,HTTP PUT 方法的含义和 Java Map 中的 put 方法是一致的。下面是 Java Doc 的摘录。

V put(K key, V value)

Associates the specified value with the specified key in this map (optional operation).
If the map previously contained a mapping for the key, the old value is replaced by the specified value.

如果从 RESTful API 的角度来理解,PUT 方法是这么工作的:

  1. 把一个对象 V 绑定到地址 K 上;今后请求地址 K 时,就会返回对象 V
  2. 如果地址 K 之前曾绑定过另一个对象,比如 V0,那么 V0 会被 V 替换。

举一个简单的例子,假设我的博客后台支持 RESTful API,我可以通过下面的请求发布这篇文章:

1
2
3
4
5
PUT https://bitmingw.com/2018/04/16/http-put-vs-post HTTP/1.1

{
/* 文章内容正文 */
}

可以看出,使用 PUT 方法时,客户端需要在 HTTP 请求中明确指定地址 K

正如 Java 的例子一样,PUT 方法应当支持幂等性。如果是同一个对象 V,PUT 多次与 PUT 一次返回的结果应该是相同的。客户端可以利用 PUT 的幂等性安全地重试请求,保证客户端的请求至少被服务端处理一次。

如果把上面发布文章的例子用 HTTP POST 方法重写,它可能会是下面这样:

1
2
3
4
5
POST https://bitmingw.com/post-article HTTP/1.1

{
/* 文章内容正文 */
}

也就是说,地址 K 不是由客户端指定的,而是由服务端生成的。比如,服务端可能会根据日期和文章标题,为本文分配一个地址。

另外,与 PUT 方法不同,POST 方法是不支持幂等性的。同一个请求被处理两次,应当生成两份对象。换句话说,客户端应该只发送一次 POST 请求,而客户端的请求至多会被服务端处理一次。

现在问题来了,如果真的遇到了网络故障,客户端应该如何重试 POST 请求呢?解决方法其实很简单,我们可以在 POST 请求中隐藏一个唯一的 token,服务端在处理请求后把 token 存入数据库,如果这个 token 之前遇到过,服务端就知道这是重复的 POST 请求,可以不再处理了。