天天看点

PUT 还是 POST ?

创建,更新与http幂等性

构建基于rest api的开发者对于何时使用http put与post有很大的误解与困惑。有些人认为post 应用于创建资源,而put则用于更新资源。其他人则认为put用于创建而post用于更改资源。这两种说法都不太确切。

通常,开发者将每个http方法与crup操作一一对应。

crud http

create post

read get

update put

delete delete

的确是这样,而且get与delete对应的操作是很明确的,但论及与create和update对应的http方法时要取决于幂等性。

状态统一性

状态统一性在http规范中是一个很重要的概念。它规定对于执行多次相同的http请求,处于服务端的资源的状态是相同的。get,head, put与delete都具有这种特性,但post没有。

为便于说明状态统一性,我们会使用一个account集合("/accounts"),并且为了简洁我们假设每个account资源都有三个属性:givenname, surname,和status。

假设你使用http put方法提交了一个update请求。在请求体中,你设置了givenname和surname的值分别为"john"和"smith"。接着你又提交了另一个http put的请求,这次你将givenname的值设置为"johnny"。它是幂等的么?不。为什么呢?因为在这两次请求的间隙,其他请求可能已经改变了account资源的服务端状态。例如,在这两次请求之间,status的值可能已经变成了“blocked"。我们示范的请求在重复提交时不能保证在服务端的account资源的状态是相同的。

请求:

这两次请求后可能的account状态。 (受其他请求的副作用影响):

引用dino chiesa所述, “put 意为提交一个资源——用一个不同的事物完全替代给定的url下的所有可访问资源。” 要使用put请求,你必须发送所有可访问属性/值,而不仅仅是你想要改变的那些。 如果我们在发送givenname和surname时加上状态值“disabled",则本次调用是幂等的并且消除了副作用。幂等性是http规范的一项基本属性,并且必须确保web的互操作性与规模。

最后,我们应该指出http状态统一性只能应用于服务端状态——非客户端。例如,某一客户端成功地发送了一个服务端状态统一请求,并立即再次发送这个请求但返回了一个错误(例如可能是由于违反了服务端某种约束),对于 http这仍是‘合法’的。因为这个请求没有对服务端资源状态产生影响,http幂等性没有破坏。

http post vs http put

既然已经清楚了状态统一性,在执行创建和更新操作时你应该使用哪个方法呢?以下是用于合理使用这些方法的快速参考。

创建

在不知道资源标识符时你应该使用post来创建资源。使用post创建资源时,返回“201 created"状态和新建资源的位置是很好的实践,因为新建资源的位置在提交时是未知的。这可以使客户端稍后访问新创建的资源如果需要的话。

响应:

201 created

当你允许客户端指定新建资源的资源标识符时要使用put。但要记住,因为put是幂等的,你必须要发送所有可能的值。

更新

你可以使用post更新全部或一部分值。

如果你想用put更新某一资源,则必须要更新资源的全部属性。你必须要在put请求中发送所有属性值以保证幂等性。

你也可以使用post发送所有值,这样服务端状态与处理put请求的结果是一样的——这不是http规范所必需的。注意幂等性与http缓存服务器的缓存有较强的关联,并且post请求通常是非缓存的。如果你对缓存的副作用感冒的话,你可以使用post来执行全部或部分更新。

post是目前惟一的状态不统一的方法。http规范对它的定义也很宽泛,并且大体上将它定义为了一个“服务端处理指令”。这就意味着在post请求中做任何处理都是“安全”的。

最后我们要注意http规范中还没有完成的另一个称为patch的方法。patch意为用于执行部分更新时的post的替代品。然而,因为post已经可以处理部分更新,http协会似乎没有急着批准和完成patch的必要了。但如果批准了,patch将会加入post作为另一个状态不统一的http方法。

继续阅读