1. 程式人生 > >Restful風格API中用put還是post做新增操作有什麼區別?

Restful風格API中用put還是post做新增操作有什麼區別?

這個是華為面試官問我的問題,回來我找了很多資料,想驗證這個問題。在回答問題之前,還需要蒐集一些基礎知識。

HTTP協議詳解

HTTP是HyperText Transfer Protocol(超文字傳輸協議)的縮寫。它的發展是全球資訊網協會(WorldWide Web Consortium)和Internet工作小組IETF(Internet Engineering Task Force)合作的結果,(他們)最終釋出了一系列的RFC,RFC 1945定義了HTTP/1.0版本。其中最著名的就是RFC 2616。RFC 2616定義了今天普遍使用的一個版本——HTTP 1.1。

HTTP協議(HyperText Transfer Protocol,超文字傳輸協議)是用於從WWW伺服器傳輸超文字到本地瀏覽器的傳送協議。它可以使瀏覽器更加高效,使網路傳輸減少。它不僅保證計算機正確快速地傳輸超文字文件,還確定傳輸文件中的哪一部分,以及哪部分內容首先顯示(如文字先於圖形)等。

HTTP協議通常承載於TCP協議之上,有時也承載於TLS或SSL協議層之上,這個時候,就成了我們常說的HTTPS。如下圖所示:

預設HTTP的埠號為80,HTTPS的埠號為443。

HTTP協議永遠都是客戶端發起請求,伺服器回送響應。見下圖:
    

這樣就限制了使用HTTP協議,無法實現在客戶端沒有發起請求的時候,伺服器將訊息推送給客戶端。

HTTP協議是一個無狀態的協議,同一個客戶端的這次請求和上次請求是沒有對應關係。

一次HTTP操作稱為一個事務,其工作過程可分為四步:

1)首先客戶機與伺服器需要建立連線。只要單擊某個超級連結,HTTP的工作開始。

2)建立連線後,客戶機發送一個請求給伺服器,請求方式的格式為:統一資源識別符號(URL)、協議版本號,後邊是MIME資訊包括請求修飾符、客戶機資訊和可能的內容。

3)伺服器接到請求後,給予相應的響應資訊,其格式為一個狀態行,包括資訊的協議版本號、一個成功或錯誤的程式碼,後邊是MIME資訊包括伺服器資訊、實體資訊和可能的內容。

4)客戶端接收伺服器所返回的資訊通過瀏覽器顯示在使用者的顯示屏上,然後客戶機與伺服器斷開連線。

如果在以上過程中的某一步出現錯誤,那麼產生錯誤的資訊將返回到客戶端,有顯示屏輸出。對於使用者來說,這些過程是由HTTP自己完成的,使用者只要用滑鼠點選,等待資訊顯示就可以了。

HTTP協議詳解之請求篇

 http請求由三部分組成,分別是:請求行、訊息報頭、請求正文

請求行以一個方法符號開頭,以空格分開,後面跟著請求的URI和協議的版本,格式如下:Method Request-URIHTTP-Version CRLF  
其中 Method表示請求方法;Request-URI是一個統一資源識別符號;HTTP-Version表示請求的HTTP協議版本;CRLF表示回車和換行(除了作為結尾的CRLF外,不允許出現單獨的CR或LF字元)。

請求方法(所有方法全為大寫)有多種,各個方法的解釋如下:
GET     請求獲取Request-URI所標識的資源
POST    在Request-URI所標識的資源後附加新的資料
HEAD    請求獲取由Request-URI所標識的資源的響應訊息報頭
PUT     請求伺服器儲存一個資源,並用Request-URI作為其標識
DELETE  請求伺服器刪除Request-URI所標識的資源
TRACE   請求伺服器回送收到的請求資訊,主要用於測試或診斷
CONNECT 保留將來使用
OPTIONS 請求查詢伺服器的效能,或者查詢與資源相關的選項和需求
應用舉例:
GET方法:在瀏覽器的位址列中輸入網址的方式訪問網頁時,瀏覽器採用GET方法向伺服器獲取資源,eg:GET /form.html HTTP/1.1 (CRLF)

POST方法要求被請求伺服器接受附在請求後面的資料,常用於提交表單。

HEAD方法與GET方法幾乎是一樣的,對於HEAD請求的迴應部分來說,它的HTTP頭部中包含的資訊與通過GET請求所得到的資訊是相同的。利用這個方法,不必傳輸整個資源內容,就可以得到Request-URI所標識的資源的資訊。該方法常用於測試超連結的有效性,是否可以訪問,以及最近是否更新。

HTTP協議詳解之響應篇

在接收和解釋請求訊息後,伺服器返回一個HTTP響應訊息。

HTTP響應也是由三個部分組成,分別是:狀態行、訊息報頭、響應正文
1、狀態行格式如下:

HTTP-VersionStatus-Code Reason-Phrase CRLF
其中,HTTP-Version表示伺服器HTTP協議的版本;Status-Code表示伺服器發回的響應狀態程式碼;Reason-Phrase表示狀態程式碼的文字描述。
狀態程式碼有三位數字組成,第一個數字定義了響應的類別,且有五種可能取值:
1xx:指示資訊--表示請求已接收,繼續處理
2xx:成功--表示請求已被成功接收、理解、接受
3xx:重定向--要完成請求必須進行更進一步的操作
4xx:客戶端錯誤--請求有語法錯誤或請求無法實現
5xx:伺服器端錯誤--伺服器未能實現合法的請求
2、常見狀態程式碼、狀態描述、說明:

請求收到,繼續處理
100——客戶必須繼續發出請求
101——客戶要求伺服器根據請求轉換HTTP協議版本
操作成功收到,分析、接受
200——交易成功
201——提示知道新檔案的URL
202——接受和處理、但處理未完成
203——返回資訊不確定或不完整
204——請求收到,但返回資訊為空
205——伺服器完成了請求,使用者代理必須復位當前已經瀏覽過的檔案
206——伺服器已經完成了部分使用者的GET請求
完成此請求必須進一步處理
300——請求的資源可在多處得到
301——刪除請求資料
302——在其他地址發現了請求資料
303——建議客戶訪問其他URL或訪問方式
304——客戶端已經執行了GET,但檔案未變化
305——請求的資源必須從伺服器指定的地址得到
306——前一版本HTTP中使用的程式碼,現行版本中不再使用
307——申明請求的資源臨時性刪除
請求包含一個錯誤語法或不能完成
400——錯誤請求,如語法錯誤
401——未授權
HTTP 401.1 - 未授權:登入失敗
  HTTP 401.2 - 未授權:伺服器配置問題導致登入失敗
  HTTP 401.3 - ACL 禁止訪問資源
  HTTP 401.4 - 未授權:授權被篩選器拒絕
HTTP 401.5 - 未授權:ISAPI 或 CGI 授權失敗
402——保留有效ChargeTo頭響應
403——禁止訪問
HTTP 403.1 禁止訪問:禁止可執行訪問
  HTTP 403.2 - 禁止訪問:禁止讀訪問
  HTTP 403.3 - 禁止訪問:禁止寫訪問
  HTTP 403.4 - 禁止訪問:要求 SSL
  HTTP 403.5 - 禁止訪問:要求 SSL128
  HTTP 403.6 - 禁止訪問:IP 地址被拒絕
  HTTP 403.7 - 禁止訪問:要求客戶證書
  HTTP 403.8 - 禁止訪問:禁止站點訪問
  HTTP 403.9 - 禁止訪問:連線的使用者過多
  HTTP 403.10 - 禁止訪問:配置無效
  HTTP 403.11 - 禁止訪問:密碼更改
  HTTP 403.12 - 禁止訪問:對映器拒絕訪問
  HTTP 403.13 - 禁止訪問:客戶證書已被吊銷
  HTTP 403.15 - 禁止訪問:客戶訪問許可過多
  HTTP 403.16 - 禁止訪問:客戶證書不可信或者無效
HTTP 403.17 - 禁止訪問:客戶證書已經到期或者尚未生效
404——沒有發現檔案、查詢或URl
405——使用者在Request-Line欄位定義的方法不允許
406——根據使用者傳送的Accept拖,請求資源不可訪問
407——類似401,使用者必須首先在代理伺服器上得到授權
408——客戶端沒有在使用者指定的餓時間內完成請求
409——對當前資源狀態,請求不能完成
410——伺服器上不再有此資源且無進一步的參考地址
411——伺服器拒絕使用者定義的Content-Length屬性請求
412——一個或多個請求頭欄位在當前請求中錯誤
413——請求的資源大於伺服器允許的大小
414——請求的資源URL長於伺服器允許的長度
415——請求資源不支援請求專案格式
416——請求中包含Range請求頭欄位,在當前請求資源範圍內沒有range指示值,請求也不包含If-Range請求頭欄位
417——伺服器不滿足請求Expect頭欄位指定的期望值,如果是代理伺服器,可能是下一級伺服器不能滿足請求長。
伺服器執行一個完全有效請求失敗
  
HTTP 500 - 內部伺服器錯誤
  HTTP 500.100 - 內部伺服器錯誤 -ASP 錯誤
  HTTP 500-11 伺服器關閉
  HTTP 500-12 應用程式重新啟動
  HTTP 500-13 - 伺服器太忙
  HTTP 500-14 - 應用程式無效
  HTTP 500-15 - 不允許請求 global.asa
  Error 501 - 未實現
       HTTP 502 - 閘道器錯誤
  HTTP 500.100 - 內部伺服器錯誤 -ASP 錯誤
  HTTP 500-11 伺服器關閉
  HTTP 500-12 應用程式重新啟動
  HTTP 500-13 - 伺服器太忙
  HTTP 500-14 - 應用程式無效
  HTTP 500-15 - 不允許請求 global.asa
  Error 501 - 未實現
       HTTP 502 - 閘道器錯誤

4 API設計的基本要求

  一個被普遍承認和遵守:RESTful設計原則。它被Roy Felding提出(在他的”基於網路的軟體架構“論文中第五章)。而REST的核心原則是將你的API拆分為邏輯上的資源。這些資源通過http被操作(GET ,POST,PUT,DELETE)。
    顯然從API使用者的角度來看,”資源“應該是個名詞。即使你的內部資料模型和資源已經有了很好的對應,API設計的時候你仍然不需要把它們一對一的都暴露出來。這裡的關鍵是隱藏內部資源,暴露必需的外部資源。
    一旦定義好了要暴露的資源,你可以定義資源上允許的操作,以及這些操作和你的API的對應關係:

·       GET /tickets # 獲取ticket列表

·       GET /tickets/12 # 檢視某個具體的ticket

·       POST /tickets # 新建一個ticket

·       PUT /tickets/12 # 更新ticket 12.

·       DELETE /tickets/12 #刪除ticekt 12

可以看出使用REST的好處在於可以充分利用http的強大實現對資源的CURD功能。而這裡你只需要一個endpoint:/tickets,再沒有其他什麼命名規則和url規則了,cool!
    但是有的endpoint,需要使用複數使得你的URL更加規整。這讓API使用者更加容易理解,對開發者來說也更容易實現。
如何處理關聯?關於如何處理資源之間的管理REST原則也有相關的描述:

·       GET /tickets/12/messages- Retrieves list of messages forticket #12

·       GET /tickets/12/messages/5- Retrieves message #5 forticket #12

·       POST /tickets/12/messages- Creates a new message inticket #12

·       PUT /tickets/12/messages/5- Updates message #5 for ticket#12

·       PATCH /tickets/12/messages/5- Partially updates message#5 for ticket #12

·       DELETE /tickets/12/messages/5- Deletes message #5 forticket #12

其中,如果這種關聯和資源獨立,那麼我們可以在資源的輸出表示中儲存相應資源的endpoint。然後API的使用者就可以通過點選連結找到相關的資源。如果關聯和資源聯絡緊密。資源的輸出表示就應該直接儲存相應資源資訊。(例如這裡如果message資源是獨立存在的,那麼上面 GET/tickets/12/messages就會返回相應message的連結;相反的如果message不獨立存在,他和ticket依附存在,則上面的API呼叫返回直接返回message資訊)

5 get和post區別

常用的請求方式是GET和POST.

GET方式:是以實體的方式得到由請求URI所指定資源的資訊,如果請求URI只是一個數據產生過程,那麼最終要在響應實體中返回的是處理過程的結果所指向的資源,而不是處理過程的描述。

POST方式:用來向目的伺服器發出請求,要求它接受被附在請求後的實體,並把它當作請求佇列中請求URI所指定資源的附加新子項,Post被設計成用統一的方法實現下列功能:

1)對現有資源的解釋;

2)向電子公告欄、新聞組、郵件列表或類似討論組發信息;

3)提交資料塊;

4)通過附加操作來擴充套件資料庫 。

從上面描述可以看出,Get是向伺服器發索取資料的一種請求;而Post是向伺服器提交資料的一種請求,要提交的資料位於資訊頭後面的實體中。

GET與POST方法有以下區別:

1)   在客戶端,Get方式在通過URL提交資料,資料在URL中可以看到;POST方式,資料放置在HTMLHEADER內提交。

2)  GET方式提交的資料最多隻能有1024位元組,而POST則沒有此限制。

3)   安全性問題。正如在(1)中提到,使用 Get 的時候,引數會顯示在位址列上,而 Post 不會。所以,如果這些資料是中文資料而且是非敏感資料,那麼使用 get;如果使用者輸入的資料不是中文字元而且包含敏感資料,那麼還是使用 post為好。

4)   安全的和冪等的。所謂安全的意味著該操作用於獲取資訊而非修改資訊。冪等的意味著對同一 URL 的多個請求應該返回同樣的結果。完整的定義並不像看起來那樣嚴格。換句話說,GET 請求一般不應產生副作用。從根本上講,其目標是當用戶開啟一個連結時,她可以確信從自身的角度來看沒有改變資源。比如,新聞站點的頭版不斷更新。雖然第二次請求會返回不同的一批新聞,該操作仍然被認為是安全的和冪等的,因為它總是返回當前的新聞。反之亦然。POST 請求就不那麼輕鬆了。POST 表示可能改變伺服器上的資源的請求。仍然以新聞站點為例,讀者對文章的註解應該通過 POST 請求實現,因為在註解提交之後站點已經不同了(比方說文章下面出現一條註解)。

6 put和post區別

有的觀點認為,應該用POST來建立一個資源,用PUT來更新一個資源;有的觀點認為,應該用PUT來建立一個資源,用POST來更新一個資源;還有的觀點認為可以用PUT和POST中任何一個來做建立或者更新一個資源。這些觀點都只看到了風格,爭論起來也只是爭論哪種風格更好,其實,用PUT還是POST,不是看這是建立還是更新資源的動作,這不是風格的問題,而是語義的問題。
 舉一個簡單的例子,假如有一個部落格系統提供一個Web API,模式是這樣http://superblogging/blogs/{blog-name},很簡單,將{blog-name}
替換為我們的blog名字,往這個URI傳送一個HTTP PUT或者POST請求,HTTP的body部分就是博文,這是一個很簡單的REST API例子。我們應該用
PUT方法還是POST方法?取決於這個REST服務的行為是否是idempotent的,假如我們傳送兩個http://superblogging/blogs/post/Sample請求,服
務器端是什麼樣的行為?如果產生了兩個部落格帖子,那就說明這個服務不是idempotent的,因為多次使用產生了副作用了嘛;如果後一個請求把第一個
請求覆蓋掉了,那這個服務就是idempotent的。前一種情況,應該使用POST方法,後一種情況,應該使用PUT方法。

參考資料:

http://www.ruanyifeng.com/blog/2011/09/restful

http://kb.cnblogs.com/page/512047/