在 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 方法是这么工作的:
- 把一个对象
V
绑定到地址K
上;今后请求地址K
时,就会返回对象V
。 - 如果地址
K
之前曾绑定过另一个对象,比如V0
,那么V0
会被V
替换。
举一个简单的例子,假设我的博客后台支持 RESTful API,我可以通过下面的请求发布这篇文章:
1 | 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 | POST https://bitmingw.com/post-article HTTP/1.1 |
也就是说,地址 K
不是由客户端指定的,而是由服务端生成的。比如,服务端可能会根据日期和文章标题,为本文分配一个地址。
另外,与 PUT 方法不同,POST 方法是不支持幂等性的。同一个请求被处理两次,应当生成两份对象。换句话说,客户端应该只发送一次 POST 请求,而客户端的请求至多会被服务端处理一次。
现在问题来了,如果真的遇到了网络故障,客户端应该如何重试 POST 请求呢?解决方法其实很简单,我们可以在 POST 请求中隐藏一个唯一的 token,服务端在处理请求后把 token 存入数据库,如果这个 token 之前遇到过,服务端就知道这是重复的 POST 请求,可以不再处理了。