爲何 HTTP PATCH 方法不是冪等的及其延伸

冪等性

首先來看什麼是冪等性,根據 rfc2616(Hypertext Transfer Protocol -- HTTP/1.1) 文檔第 50 頁底部對 Idempotent Methods 的定義:html

Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request.數據庫

翻譯過來也就是:相同的請求執行屢次和執行一次的反作用是同樣的後端

段落接下來就給出了具備冪等性的方法:api

The methods GET, HEAD, PUT and DELETE share this property. Also, the methods OPTIONS and TRACE SHOULD NOT have side effects, and so are inherently idempotent.服務器

能夠看出,GETHEADPUTDELETEOPTIONSTRACE 方法都是冪等的。app

PUT 和 PATCH

根據約定( Convention ),PUT 方法用於更新數據,PATCH 方法也用於更新數據,爲何 PUT 方法是冪等的而 PATCH 方法不是冪等的呢?咱們繼續研究文檔(第54頁):ide

The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI.post

PUT 方法將請求所包含的實體存儲在所提供的 Request-URI 下。若是該 URI 指代一個已經存在的資源,那麼請求中的實體應該被視爲保存在原服務器上的實體的修改版本。若是 Request-URI 沒有指向一個現有資源,而且該 URI 能夠被髮送請求的用戶代理定義爲新資源,則原服務器可使用該 URI 來建立資源。this

這裏說的很明白了,PUT 用作更新操做的時候是提交一整個更新後的實體,而不是須要修改的實體中的部分屬性。當 URI 指向一個存在的資源,服務器要作的事就是查找並替換。翻譯

接下來看 PATCH(PATCH 方法在原文檔中沒有找到相關描述,後來發如今另外一個 RFC 裏面 - RFC5789):

The PATCH method requests that a set of changes described in the request entity be applied to the resource identified by the Request-URI. The set of changes is represented in a format called a "patch document" identified by a media type. If the Request-URI does not point to an existing resource, the server MAY create a new resource, depending on the patch document type (whether it can logically modify a null resource) and permissions, etc.

PATCH 方法請求將一組描述在請求實體裏的更改應用到 Request-URI 標誌的資源。這組更改以稱爲 "補丁文檔" 的格式(該格式由媒體類型標誌)表示,若是 Request-URI 未指向現有資源,服務器可能根據補丁文檔的類型(是否能夠在邏輯上修改空資源)和權限等來建立一個新資源。

因此能夠知道 PATCH 請求中的實體是一組將要應用到實體的更改,而不是像 PUT 請求那樣是要替換舊資源的實體,可是這並無解決 PATCH 方法爲何不是冪等的問題。不着急,繼續讀,接下來就給出了 PUT 和 PATCH 的區別:

The difference between the PUT and PATCH requests is reflected in the way the server processes the enclosed entity to modify the resource identified by the Request-URI. In a PUT request, the enclosed entity is considered to be a modified version of the resource stored on the origin server, and the client is requesting that the stored version be replaced. With PATCH, however, the enclosed entity contains a set of instructions describing how a resource currently residing on the origin server should be modified to produce a new version. The PATCH method affects the resource identified by the Request-URI, and it also MAY have side effects on other resources; i.e., new resources may be created, or existing ones modified, by the application of a PATCH.

PUT 和 PATCH 請求的區別體如今服務器處理封閉實體以修改 Request-URI 標誌的資源的方式。在一個 PUT 請求中,封閉實體被認爲是存儲在源服務器上的資源的修改版本,而且客戶端正在請求替換存儲的版本。而對於 PATCH 請求,封閉實體中包含了一組描述當前保留在源服務器上的資源應該如何被修改來產生一個新版本的指令。PATCH 方法影響由 Request-URI 標誌的資源,並且它也可能對其餘資源有反作用;也就是,經過使用 PATCH,新資源可能被創造,或者現有資源被修改。

以上就是答案。能夠理解爲,PATCH 請求中的實體保存的是修改資源的指令,該指令指導服務器來對資源作出修改,因此不是冪等的。
可能有點抽象,打個比方:對於存在服務器中的 A 對象有個屬性 B 爲 1,若是要修改 B 屬性爲 3,則 PUT 請求是直接將修改過 B 屬性的整個新對象發送給服務器查找並替換。而 PATCH 請求是在實體中包含指令 --- 將 A 對象中 B 屬性的值加 2,那麼若是該請求被執行屢次的話,B 屬性就可能不爲 3 了,而 PUT 請求不論執行多少次,B 屬性永遠都是 3,因此說 PUT 方法是冪等的,而 PATCH 方法不是冪等的。

PUT 和 POST

在看請求相關的帖子的時候,偶爾也會看見爭論說使用 PUT 來新增資源,使用 POST 來修改資源,或者說這兩個方法差異不大,不必這麼明確分工。上文也提到了 PUT 方法的 URI 指向的資源不存在的時候也能夠建立新資源。那到底怎麼用,都寫到這裏了繼續是用文檔來講話,有關 POST 方法的說明:

The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line. POST is designed to allow a uniform method to cover the following functions:

  • Annotation of existing resources;
  • Posting a message to a bulletin board, newsgroup, mailing list or similar group of articles;
  • Providing a block of data, such as the result of submitting a form, to a data-handling process;
  • Extending a database through an append operation.

The actual function performed by the POST method is determined by the server and is usually dependent on the Request-URI. The posted entity is subordinate to that URI in the same way that a file is subordinate to a directory containing it, a news article is subordinate to a newsgroup to which it is posted, or a record is subordinate to a database.

POST 方法用於請求源服務器接受請求中的實體做爲 Request-URI 所標誌的資源的新下級。 POST 方法旨在容許一個統一的方法來涵蓋如下功能:

  • 現有資源的註釋;
  • 在公告欄,新聞組,郵件列表或相似文章組中發佈消息;
  • 提供數據塊,例如提交表單的結果,數據處理過程;
  • 經過追加操做擴展數據庫。

POST方法執行的實際功能由服務器肯定,一般依賴於 Request-URI。 發佈的實體從屬於該 URI,其方式與文件從屬於包含它的目錄相同,新聞文章從屬於發佈它的新聞組,或者記錄從屬於數據庫。

加黑的第一句話是否是很熟悉,用 RESTful API 實現先後端交互接口的朋友看到這裏應該就清楚了。這也是爲何 POST /api/articles 在 RESTful 中被建議用來建立文章而不是更新文章的緣由。此外,POST 請求不是冪等的,覺得着若是把它用來看成資源更新操做,會創造多個相同的資源,這是更新操做不但願產生的反作用,因此仍是用 POST 新增資源,PUT 更新資源吧。

固然,這些都是約定( convertion ) 而不是規定( standard ),若是你就是喜歡用 PUT 新建資源,POST 來修改資源,那我只能說對不起讓你花這麼長時間看篇文章了,僅僅使用 GET 和 POST 完成全部操做也還大有人在😄😄。

相關文章
相關標籤/搜索