小村軟體有限公司
第 2 章

HTTP 方法 — 安全與冪等這兩個約定

依「想做什麼」區分使用 GET・POST・PUT・DELETE・HEAD,並用安全(不改變伺服器狀態)與冪等(做幾次結果都相同)這 2 個約定畫出界線,讓它能用於重試的判斷。

是不是「反正全部用 POST」在開發?

表單也好、取得也好、刪除也好,因為能動就全部用 POST 做掉。或者反過來,送出按鈕被再點一次,訂單就被重複登錄了兩筆,卻找不到原因 — 方法的使用區分,正因為只求「能動」時再含糊也能過關,所以總是在出事之後才顯出它的重要。

如上一章所讀,位於請求行開頭的方法,是往返書信的動詞。HTTP 的方法有很多個,但一開始只要能區分使用這 5 個就足夠了。

GET
「請給我這個」— 資源的取得。開啟頁面、讀取圖片、從 API 取得清單
HEAD
「給我和 GET 相同的回答,但去掉本文」— 只想確認大小或更新日期等標頭時
POST
「請處理這個」— 表單送出、新增建立、其他處理委託。效果可能隨每次執行而累積
PUT
「請把這個 URL 的內容,變成這份內容」— 指定了目的地的置換(覆寫儲存)
DELETE
「請刪除這個 URL 的東西」— 刪除的請託

例如 PUT /users/42/profile 是「把 42 號使用者的個人資料變成這份內容」,POST /orders 是「處理這份訂購內容並建立新訂單」。目的地已定的置換用 PUT,會新生出東西的或處理的委託用 POST,這是基本的使用區分。

練習 2-1 — 區分使用 5 個動詞

從「想做什麼」出發,練習選出合適的方法。

Q1. 在網路商店 https://shop.example.com,要送出訂購表單填寫的內容並建立一筆新訂單時,最合適的方法是哪一個?

Q2. 對於一個巨大的影片檔,不想下載、只想知道大小或更新日期時,最合適的方法是哪一個?

Q3. PUT 與 POST 差異的說明,最合適的是哪一個?

2 個約定 — 安全與冪等

比起背下 5 個動詞,更重要的是繫在方法身上的2 個約定。這 2 個詞在規格書與錯誤調查中都頻繁出現。

安全(safe)— 不改變伺服器的狀態
「只讀取」的約定。GET 與 HEAD 屬於此類。呼叫幾次伺服器的資料都不會變
冪等(idempotent)— 做幾次最終狀態都相同
執行 1 次或執行 10 次,伺服器的最終狀態都相同的約定。除了 GET・HEAD,PUT 與 DELETE 也屬於此類

在這裡動手確認一下。用 PUT /users/42/profile 把資料置換成「姓名 = 小村」的請求送 3 次,最終狀態仍是「姓名 = 小村」— 和送 1 次相同。DELETE /orders/7 送 2 次,「7 號訂單已消失」這個最終狀態也相同(第 2 次也許會回 404,但冪等性看的是伺服器端的最終狀態)。另一方面,POST /orders 送 3 次就會產生 3 筆訂單 — POST 不是冪等的。

整理彼此的關係:安全就必定冪等(既然什麼都不改變,做幾次當然都相同)。反過來不成立,PUT 與 DELETE 是「會改變,但做幾次都相同」— 冪等但不安全,落在中間的帶狀區域。

針對 GET・HEAD・POST・PUT・DELETE 各個 HTTP 方法,對應出是否安全・是否冪等・主要用途的表格

把 5 個方法沿著安全・冪等 2 個軸排列的地圖。GET/HEAD 遵守兩個約定,PUT/DELETE 只有冪等,POST 兩個約定都不做。這張地圖就是「可以重試嗎」的判斷表。

在實務上的效果 — 更新的重試,先確認冪等性

這 2 個約定在實務上最有效的場面,是通訊失敗時重送(重試)的判斷

送出請求後逾時,其實存在 2 種可能:「請求沒有送達伺服器」,還是「送達了、處理也完成了,只有回覆遺失了」— 從用戶端無法區分。這時冪等性就派上用場。

冪等的方法(GET/HEAD/PUT/DELETE)
就算已被處理,重送後最終狀態也不變。可以放心重試
不冪等的方法(POST)
如果已被處理,重送就成了雙重處理(訂單 2 筆・付款 2 次)。無條件的重試很危險

正因如此,瀏覽器在 POST 的結果頁面按重新整理時,才會特地確認「要重新送出表單嗎?」(這個場面會在第 7 章的案例中再次登場)。此外,內建自動重試的程式庫多半預設只重送 GET,依據也是這個約定。「更新的重試,先確認那個方法是否冪等」 — 請默唸到手能記住為止。

練習 2-2 — 畫出安全與冪等的界線

精確說出 2 個約定的差別,並連結到實務上的「可以重試嗎」。

Q4. 方法是「安全(safe)」的,指的是什麼樣的約定?

Q5. 「冪等(idempotent)但不安全」的方法組合是哪一個?

Q6. 送出更新類的 API 請求後,沒有收到回應而逾時了。在再送一次相同請求之前,最應該確認的是哪一個?

本章帶回家的重點

  • 方法是往返書信的動詞。取得用 GET,不含本文的確認用 HEAD,處理委託・新增建立用 POST,指定目的地的置換用 PUT,刪除用 DELETE
  • 安全 = 不改變伺服器的狀態(GET/HEAD)。冪等 = 做幾次最終狀態都相同(GET/HEAD/PUT/DELETE)。安全就必定冪等
  • POST 既不安全也不冪等。逾時後的無條件重試有雙重處理的危險
  • 更新的重試,先確認冪等性 — 這一句話就是在實務上的效果

請託的讀法已經上手,下一章是往返書信的另一側 — 來自伺服器的回覆。從百位數開始,依序解讀 3 位數的狀態碼。