http - put方法 - restful get




REST中的PUT與POST (20)

源服務器可以使用該URI創建資源

因此,您可以使用POST,但可能不需要PUT來創建資源。您不必同時支持兩者。對我來說,POST就足夠了。所以這是一個設計決定。

正如您的報價所提到的,您使用PUT創建沒有分配給IRI的資源,並且您仍然想要創建資源。例如,PUT /users/123/password通常用新密碼替換舊密碼,但如果密碼已經不存在(例如,由新註冊的用戶或通過恢復被禁用的用戶),則可以使用它來創建密碼。

根據HTTP / 1.1規範:

POST方法用於請求源服務器接受請求中包含的實體作為Request-Line Request-URI標識的資源的新下級

換句話說, POST用於創建

PUT方法請求將所包含的實體存儲在提供的Request-URI 。 如果Request-URI引用已經存在的資源,則封閉的實體應該被視為駐留在源服務器上的實體的修改版本。 如果Request-URI沒有指向現有資源,並且該URI能夠被請求用戶代理定義為新資源,則源服務器可以使用該URI創建資源。

也就是說, PUT用於創建或更新

那麼,應該使用哪一個來創建資源? 或者需要支持兩者?


摘要:

創建:

可以通過以下方式使用PUT或POST執行:

使用newResourceId作為標識符,在/ resources URI或集合下創建新資源。

PUT /resources/<newResourceId> HTTP/1.1 

POST

在/ resources URI或集合下創建新資源。 通常,服務器返回標識符。

POST /resources HTTP/1.1

更新:

只能通過以下方式使用PUT執行:

使用existingResourceId作為標識符,在/ resources URI或集合下更新資源。

PUT /resources/<existingResourceId> HTTP/1.1

說明:

在處理REST和URI時,您可以在左側使用泛型 ,在右側使用 特定的。 泛型通常稱為集合 ,更具體的項稱為資源 。 請注意, 資源可以包含集合

例子:

< - generic - specific - >

URI: website.com/users/john
website.com  - whole site
users        - collection of users
john         - item of the collection, or a resource

URI:website.com/users/john/posts/23
website.com  - whole site
users        - collection of users
john         - item of the collection, or a resource
posts        - collection of posts from john
23           - post from john with identifier 23, also a resource

當你使用POST時,你總是引用一個集合 ,所以每當你說:

POST /users HTTP/1.1

您要將新用戶發佈到users 集合

如果你繼續嘗試這樣的事情:

POST /users/john HTTP/1.1

它會起作用,但從語義上說,你想要將資源添加到users 集合下的john 集合中

一旦您使用PUT,您就可以在集合中引用資源或單個項目。 所以當你說:

PUT /users/john HTTP/1.1

您告訴服務器更新,或者創建它是否不存在, 用戶 集合下的john 資源

規格:

讓我重點介紹一下規範的一些重要部分:

POST

POST方法用於請求源服務器接受請求中包含的實體作為請求行中Request-URI標識的資源的下級

因此,在集合上創建新資源

PUT方法請求將所包含的實體存儲在提供的Request-URI下。 如果Request-URI引用已經存在的資源,則封閉的實體應該被視為駐留在源服務器上的實體的修改版本 。 如果Request-URI 沒有指向現有資源,並且該URI 能夠被請求用戶代理定義為資源 ,則源服務器可以使用該URI 創建資源。

因此,基於資源的存在來創建或更新。

參考:


REST是一個非常高級的概念。 事實上,它甚至根本沒有提到HTTP!

如果您對如何在HTTP中實現REST有任何疑問,可以隨時查看Atom發布協議(AtomPub)規範。 AtomPub是一個使用HTTP編寫RESTful webservices的標準,由許多HTTP和REST傑出人員開發,其中一些來自REST的發明者和HTTP本身(共同)發明者Roy Fielding的輸入。

實際上,您甚至可以直接使用AtomPub。 雖然它來自博客社區,但它絕不僅限於博客:它是一種通用協議,用於通過HTTP與任意資源的任意(嵌套)集合進行REST交互。 如果您可以將應用程序表示為嵌套的資源集合,那麼您可以使用AtomPub而不用擔心是使用PUT還是POST,要返回的HTTP狀態代碼以及所有這些詳細信息。

這就是AtomPub關於資源創建的說法(第9.2節):

要將成員添加到集合,客戶端會將POST請求發送到集合的URI。


新答案(現在我更了解REST):

PUT僅僅是服務應該從現在開始用於呈現客戶端識別的資源的表示的內容的陳述; POST是一個聲明,說明服務從現在開始應該包含哪些內容(可能是重複的),但服務器應該如何識別該內容。

PUT x(如果x標識resource):“替換由x我的內容標識的資源的內容。”

PUT x(如果x未標識資源):“創建包含我的內容的新資源,並使用x它來識別它。”

POST x:“存儲我的內容並給我一個標識符,我可以使用它來識別包含所述內容的資源(舊的或新的)(可能與其他內容混合在一起)。所述資源應該與x標識的資源相同或從屬。” “ ÿ的資源是從屬於X的資源”是通常但不通過使一定實施ÿ的子路徑X(例如X = /fooÿ = /foo/bar)和修改的表示(S)X的資源,以反映是否存在一個新資源的例子,例如帶有y的超鏈接的資源和一些元數據。只有後者對於良好的設計才是真正必不可少的,因為在REST中URL是不透明的 - 你應該使用超媒體而不是客戶端URL構造來遍歷服務。

在REST中,沒有包含“內容”的資源。我將“內容”稱為服務用於一致地呈現表示的數據。它通常由數據庫中的一些相關行或文件(例如圖像文件)組成。服務可以將用戶的內容轉換為服務可以使用的內容,例如將JSON有效負載轉換為SQL語句。

原始答案(可能更容易閱讀)

PUT /something(如果/something已經存在的話):“拿走你所擁有的一切,/something並用我給你的東西取而代之。”

PUT /something(如果/something還不存在的話):“把我給你的東西放進去吧/something。”

POST /something:“ /something只要你在完成後給我的URL ,就把我給你的東西放在任何你想要的地方。”


簡答:

簡單的經驗法則:使用POST創建,使用PUT進行更新。

答案很長:

POST:

  • POST用於將數據發送到服務器。
  • 資源的URL未知時很有用

放:

  • PUT用於將狀態傳輸到服務器
  • 知道資源的URL時很有用

更長的答案:

為了理解它,我們需要質疑為什麼PUT是必需的,PUT試圖解決的問題是POST不能解決的問題。

從REST架構的角度來看,沒有一個重要。我們也可以在沒有PUT的情況下生活。但從客戶端開發人員的角度來看,這使他/她的生活變得更加簡單。

在PUT之前,客戶端無法直接知道服務器生成的URL或者是否已生成任何URL,或者是否已經更新了要發送到服務器的數據。PUT解除了所有這些頭痛的開發人員。PUT是冪等的,PUT處理競爭條件,PUT允許客戶端選擇URL。


總體:

PUT和POST都可以用於創建。

你必須問“你在做什麼動作?” 區分你應該使用什麼。 我們假設您正在設計一個用於提問的API。 如果您想使用POST,那麼您可以將其添加到問題列表中。 如果你想使用PUT,你會對特定問題這樣做。

兩者都可以使用,所以我應該在我的RESTful設計中使用哪一個:

您不需要同時支持PUT和POST。

使用哪種方法取決於你。 但請記住使用正確的,具體取決於您在請求中引用的對象。

一些考慮:

  • 您是否明確指定了您創建的URL對象,還是讓服務器決定? 如果您為它們命名,那麼使用PUT。 如果您讓服務器決定然後使用POST。
  • PUT是冪等的,所以如果你將對象PUT兩次,它就沒有效果。 這是一個很好的屬性,所以我會盡可能使用PUT。
  • 您可以使用具有相同對象URL的PUT更新或創建資源
  • 使用POST,您可以同時有2個請求進行URL修改,並且可以更新對象的不同部分。

一個例子:

我寫了以下內容作為SO的另一個答案的一部分

POST:

用於修改和更新資源

POST /questions/<existing_question> HTTP/1.1
Host: www.example.com/

請注意以下是一個錯誤:

POST /questions/<new_question> HTTP/1.1
Host: www.example.com/

如果尚未創建URL,則在指定名稱時不應使用POST來創建URL。 這會導致“找不到資源”錯誤,因為<new_question>尚不存在。 您應該首先在服務器上輸入<new_question>資源。

你可以做這樣的事情來使用POST創建資源:

POST /questions HTTP/1.1
Host: www.example.com/

請注意,在這種情況下,未指定資源名稱,將返回新對象URL路徑。

放:

用於創建資源或覆蓋它。 在指定資源新URL時。

對於新資源:

PUT /questions/<new_question> HTTP/1.1
Host: www.example.com/

要覆蓋現有資源:

PUT /questions/<existing_question> HTTP/1.1
Host: www.example.com/

以一種非常簡單的方式,我以Facebook時間表為例。

案例1:當您在時間軸上發佈內容時,這是一個全新的條目。所以在這種情況下,他們使用POST方法,因為POST方法是非冪等的。

案例2:如果您的朋友第一次對您的帖子發表評論,那麼也會在數據庫中創建一個新條目,以便使用POST方法。

案例3:如果您的朋友編輯了他的評論,在這種情況下,他們有一個評論ID,因此他們將更新現有評論,而不是在數據庫中創建新條目。因此,對於這種類型的操作,使用PUT方法,因為它是冪等的。*

在單行線,使用POST來添加新條目的數據庫和PUT更新數據庫中的東西。


你可以在網上找到斷言

兩者都不對。

最好是根據動作的idempotence性在PUT和POST之間進行選擇。

PUT意味著放置一個資源 - 用不同的東西完全替換給定URL上的任何可用資源。 根據定義,PUT是冪等的。 你喜歡這麼多次,結果是一樣的。 x=5是冪等的。 無論以前是否存在,您都可以投入資源(例如,創建或更新)!

POST更新資源,添加輔助資源或導致更改。 POST不是冪等的,就像x++不是冪等的一樣。

通過這個論點,PUT用於在您知道要創建的事物的URL時創建。 當您知道要創建的事物類別的“工廠”或管理員的URL時,可以使用POST創建。

所以:

POST /expense-report

要么:

PUT  /expense-report/10929

兩者都用於客戶端到服務器之間的數據傳輸,但它們之間存在細微差別,它們是:

比喻:

  • PUT即拿走並放置它的位置。
  • POST作為郵局發送郵件。


大多數時候,你會像這樣使用它們:

  • POST資源到一個集合
  • PUT由collection /:id標識的資源

例如:

  • POST / items
  • PUT / items / 1234

在這兩種情況下,請求正文都包含要創建或更新的資源的數據。從路由名稱中可以明顯看出POST不是冪等的(如果你調用它3次就會產生3個對象),但是PUT是冪等的(如果你稱之為3次,結果是相同的)。 PUT通常用於“upsert”操作(創建或更新),但如果您只想使用它來修改,則總是可以返回404錯誤。

請注意,POST“創建”集合中的新元素,PUT“替換”給定URL處的元素,但使用PUT進行部分修改是一種非常常見的做法,即僅將其用於更新現有資源和僅修改正文中包含的字段(忽略其他字段)。這在技術上是不正確的,如果你想要REST-purist,PUT應該替換整個資源,你應該使用PATCH進行部分更新。就我們所有API端點的行為清晰且一致而言,我個人並不在意。

請記住,REST是一組保持API簡單的約定和指南。如果您最終只是為了檢查“RESTfull”框而進行複雜的解決方案,那麼您就是在挫敗目的;)


我想補充一下我的“務實”建議。 當您知道可以檢索要保存的對象的“id”時,請使用PUT。 如果您需要返回數據庫生成的ID以供將來查找或更新,則使用PUT將無法正常工作。

因此:要保存現有用戶,或者客戶端生成ID的用戶,並且已驗證該ID是唯一的:

PUT /user/12345 HTTP/1.1  <-- create the user providing the id 12345
Host: mydomain.com

GET /user/12345 HTTP/1.1  <-- return that user
Host: mydomain.com

否則,使用POST初始創建對象,並使用PUT更新對象:

POST /user HTTP/1.1   <--- create the user, server returns 12345
Host: mydomain.com

PUT /user/12345 HTTP/1.1  <--- update the user
Host: mydomain.com

我打算用以下內容登陸:

PUT是指由URI標識的資源。在這種情況下,您正在更新它。它是三個動詞中引用資源的一部分 - 刪除並成為另外兩個。

POST基本上是一種自由形式的消息,其含義被定義為“帶外”。如果消息可以解釋為向目錄添加資源,那就沒問題,但基本上您需要了解要發送(發布)的消息以了解資源會發生什麼。

因為PUT和GET和DELETE是指資源,所以它們也是冪等的。

POST可以執行其他三個功能,但隨後請求的語義將丟失在緩存和代理等中介上。這也適用於在資源上提供安全性,因為帖子的URI不一定表示它正在應用的資源(儘管如此)。

PUT不需要是一個創造; 如果資源尚未創建,則服務可能會出錯,但否則會更新它。反之亦然 - 它可能會創建資源,但不允許更新。PUT唯一需要的是它指向特定資源,其有效負載是該資源的表示。成功的PUT意味著(禁止干擾)GET將檢索相同的資源。

編輯:還有一件事 - PUT可以創建,但如果確實如此,則ID必須是自然ID - AKA是電子郵件地址。這樣,當你PUT兩次時,第二次放置是第一次更新。這使它成為冪等的

如果生成了ID(例如,新的員工ID),則具有相同URL的第二個PUT將創建違反冪等規則的新記錄。在這種情況下,動詞將是POST,而消息(不是資源)將使用此消息中定義的值創建資源。


語義應該是不同的,因為“PUT”,如“GET”應該是冪等的 - 意思是,你可以多次執行相同的PUT請求,結果就像你只執行一次一樣。

我將描述我認為最廣泛使用且最有用的約定:

當您在特定URL上放置資源時,會發生的事情是它應該保存在該URL,或者沿著這些行保存。

當您對特定URL上的資源進行POST時,通常會向該URL發布相關信息。這意味著URL上的資源已經存在。

例如,當您想要創建新流時,可以將其設置為某個URL。但是,當您要將消息發佈到現有流時,請POST到其URL。

至於修改流的屬性,可以使用PUT或POST執行此操作。基本上,只有當操作是冪等時才使用“PUT” - 否則使用POST。

但請注意,並非所有現代瀏覽器都支持GET或POST以外的HTTP謂詞。


這是一個簡單的規則:

PUT到URL應該用於更新或創建可以位於該URL的資源。

應該使用POST到URL來更新或創建位於其他(“從屬”)URL的資源,或者不能通過HTTP定位。


雖然可能有一種不可知的方式來描述這些,但它似乎與網站答案中的各種陳述相衝突。

讓我們在這裡非常明確和直接。如果您是使用Web API的.NET開發人員,事實是(來自Microsoft API文檔),http://www.asp.net/web-api/overview/creating-web-apis/creating-a-web-api-that-supports-crud-operations

1. PUT = UPDATE (/api/products/id)
2. MCSD Exams 2014 -  UPDATE = PUT, there are **NO** multiple answers for that question period.

當然,您“可以”使用“POST”進行更新,但只需遵循您給定框架為您規定的約定。在我的例子中它是.NET / Web API,所以PUT用於UPDATE沒有爭論。

我希望這可以幫助任何閱讀Amazon和Sun / Java網站鏈接所有評論的Microsoft開發人員。


POST就像在郵箱中發信或將電子郵件發送到電子郵件隊列。PUT就像你把一個物體放在一個小房間或一個架子上的地方(它有一個已知的地址)。

使用POST,您將發佈到QUEUE或COLLECTION的地址。使用PUT,您可以使用ITEM的地址。

PUT是冪等的。您可以發送請求100次,這無關緊要。POST不是冪等的。如果您發送請求100次,您將在郵政信箱中收到100封電子郵件或100封信件。

一般規則:如果您知道項目的ID或名稱,請使用PUT。如果您希望接收方分配項目的ID或名稱,請使用POST。


對於什麼時候使用HTTP POST而不是HTTP PUT方法來解決REST服務似乎總是存在一些混淆。大多數開發人員會嘗試將CRUD操作直接關聯到HTTP方法。我認為這是不正確的,並且不能簡單地將CRUD概念與HTTP方法相關聯。那是:

Create => HTTP PUT
Retrieve => HTTP GET
Update => HTTP POST
Delete => HTTP DELETE

確實,CRUD操作的R(etrieve)和D(elete)可以分別直接映射到HTTP方法GET和DELETE。但是,混淆在於C(reate)和U(更新)操作。在某些情況下,可以使用PUT進行創建,而在其他情況下,則需要POST。模糊性在於HTTP PUT方法與HTTP POST方法的定義。

根據HTTP 1.1規範,GET,HEAD,DELETE和PUT方法必須是冪等的,POST方法不是冪等的。也就是說,如果操作可以在資源上執行一次或多次並且總是返回該資源的相同狀態,則該操作是冪等的。而非冪等操作可以將資源的修改狀態從一個請求返回到另一個請求。因此,在非冪等操作中,不能保證一個人將獲得相同的資源狀態。

基於上面的冪等定義,我使用HTTP PUT方法與使用HTTP POST方法進行REST服務的方法是:在以下情況下使用HTTP PUT方法:

The client includes all aspect of the resource including the unique identifier to uniquely identify the resource. Example: creating a new employee.
The client provides all the information for a resource to be able to modify that resource.This implies that the server side does not update any aspect of the resource (such as an update date).

在這兩種情況下,可以使用相同的結果多次執行這些操作。也就是說,不會通過多次請求操作來更改資源。因此,一個真正的冪等操作。在以下情況下使用HTTP POST方法:

The server will provide some information concerning the newly created resource. For example, take a logging system. A new entry in the log will most likely have a numbering scheme which is determined on the server side. Upon creating a new log entry, the new sequence number will be determined by the server and not by the client.
On a modification of a resource, the server will provide such information as a resource state or an update date. Again in this case not all information was provided by the client and the resource will be changing from one modification request to the next. Hence a non idempotent operation.

結論

不要直接關聯CRUD操作並將其映射到REST服務的HTTP方法。使用HTTP PUT方法與HTTP POST方法應該基於該操作的冪等方面。也就是說,如果操作是冪等的,那麼使用HTTP PUT方法。如果操作是非冪等的,則使用HTTP POST方法。


對這個主題不熟悉的讀者會被關於你該做什麼的無休止討論以及相對缺乏經驗教訓所震驚。我認為,REST比SOAP更“優先”的事實是從經驗中獲得高水平的學習,但我們必須從那裡取得進步?這是2016年。羅伊的論文是在2000年。我們開發了什麼?它有趣嗎?是否易於集成?支持?它會處理智能手機和移動連接的崛起嗎?

根據ME,現實生活中的網絡是不可靠的。請求超時。連接已重置。網絡一次下降數小時或數天。火車進入隧道與移動用戶搭乘。對於任何給定的請求(在所有這些討論中偶爾都會承認),請求可以在途中落入水中,或者響應可以在返回途中落入水中。在這些情況下,直接針對實質性資源發出PUT,POST和DELETE請求一直讓我覺得有點野蠻和天真。

HTTP沒有做任何事情來確保請求響應的可靠完成,這很好,因為這恰好是網絡感知應用程序的工作。開發這樣的應用程序,你可以跳過箍使用PUT而不是POST,然後更多的箍在服務器上發出某種錯誤,如果你檢測到重複的請求。回到客戶端,然後你必須跳過箍來解釋這些錯誤,重新獲取,重新驗證和重新發布。

或者您可以這樣做:將您的不安全請求視為短暫的單用戶資源(讓我們稱之為操作)。客戶端在實體資源上請求新的“操作”,對資源進行空POST。 POST將僅用於此目的。一旦安全地擁有新鮮動作的URI,客戶端就將不安全的請求PUT發送到動作URI,而不是目標資源。解決操作並更新“真實”資源恰好是API的工作,並且在這裡與不可靠的網絡分離。

服務器執行業務,返迴響應並將其存儲在約定的操作URI中。如果出現任何問題,客戶端會重複請求(自然行為!),如果服務器已經看到它,它會重複存儲的響應並且不執行任何其他操作

您將很快發現與promises的相似性:我們在執行任何操作之前創建並返回結果的佔位符。也像承諾一樣,動作可以成功或失敗一次,但其結果可以重複獲取。

最重要的是,我們為發送和接收應用程序提供了將唯一標識的操作與其各自環境中的唯一性相關聯的機會。我們可以開始要求並執行!來自客戶的負責任行為:盡可能多地重複您的請求,但在您擁有現有結果的確定結果之前不要生成新的操作。

因此,許多棘手的問題消失了。重複插入請求不會創建重複項,並且在我們擁有數據之前,我們不會創建真實資源。(數據庫列可以保持不可為空)。重複更新請求不會遇到不兼容的狀態,也不會覆蓋後續更改。客戶端可以(重新)獲取並無縫處理原始確認,無論出於何種原因(客戶端崩潰,響應丟失等)。

連續刪除請求可以查看和處理原始確認,而不會遇到404錯誤。如果事情花費的時間超過預期,我們可以暫時回复,我們有一個地方,客戶可以檢查確定的結果。這種模式中最好的部分是它的功夫(熊貓)屬性。我們採取了一個弱點,即客戶在不理解響應的情況下重複請求的傾向,並將其變為強度 :-)

在告訴我這不是RESTful之前,請考慮REST原則的眾多方式。客戶端不構造URL。雖然語義上有一點變化,但API仍然是可發現的。適當使用HTTP謂詞。如果你認為這是一個巨大的改變,我可以從經驗告訴你,它不是。

如果您認為要存儲大量數據,那就讓我們來談談:典型的更新確認只是一個千字節的一小部分。HTTP目前為您提供一兩分鐘的明確回應。即使您只存儲一周的行動,客戶也有足夠的機會趕上。如果您的產量非常高,您可能需要一個專用的符合酸的鍵值存儲或內存解決方案。


最重要的考慮因素是可靠性。如果POST消息丟失,則係統狀態未定義。自動恢復是不可能的。對於PUT消息,只有在第一次成功重試之前,狀態才是未定義的。

例如,使用POST創建信用卡交易可能不是一個好主意。

如果您的資源上碰巧有自動生成的URI,您仍然可以通過將生成的URI(指向空資源)傳遞給客戶端來使用PUT。

其他一些考慮:

  • POST使整個包含資源的緩存副本無效(更好的一致性)
  • POST請求時PUT響應不可緩存(需要內容位置和到期)
  • PME受Java ME,舊瀏覽器,防火牆等的支持較少

有可能重述已經說過的內容,重要的是要記住,PUT意味著客戶端在創建資源時控制URL最終會成為什麼。因此,PUTPOST之間的選擇部分將取決於您可以信任客戶端提供多少正確的,規範化的URL,這些URL與您的URL方案一致。

當您無法完全信任客戶端做正確的事情時,使用POST創建新項目然後在響應中將URL發送回客戶端會更合適。





put