如何使POST請求具有冪等性防止重複提交 - mscharhag
冪等性是一個積極的 API 特性。它有助於使 API 更具容錯性,因為客戶端可以在出現連線問題時安全地重試請求。
HTTP 規範將 GET、HEAD、OPTIONS、TRACE、PUT 和 DELETE 方法定義為冪等的。這些方法中的 GET、PUT 和 DELETE 是 REST API 中通常使用的方法。以冪等方式實現 GET、PUT 和 DELETE 通常不是什麼大問題。
POST 和 PATCH 有點不同,它們都沒有被指定為冪等的。但是,兩者都可以在冪等性方面實現,從而使客戶在出現問題時更容易。在這篇文章中,我們將探討使 POST 和 PATCH 請求冪等的不同選項。
使用唯一的業務約束
在建立新資源(通常透過 POST 表示)時提供冪等性的最簡單方法是獨特的業務約束。
例如,假設我們要建立一個需要唯一電子郵件地址的使用者資源:
POST /users { "name": "John Doe", "email": "john@doe.com" } |
如果客戶端不小心傳送了兩次此請求,則第二個請求將返回錯誤,因為具有給定電子郵件地址的使用者已存在。在這種情況下,通常會返回 HTTP 400(錯誤請求)或 HTTP 409(衝突)作為狀態程式碼。
請注意,用於提供冪等性的約束不必是請求正文的一部分。URI 部分和關係也有助於形成唯一約束。
一個很好的例子是與父資源以一對一關係關聯的資源。例如,假設我們要使用給定的訂單 ID 支付訂單。
付款請求可能如下所示:
POST /order/<order-id>/payment { ... (payment details) } |
一個訂單隻能支付一次,因此/payment與其父資源/order/<order-id> 是一對一的關係。如果給定訂單已經存在付款,則伺服器可以拒絕任何進一步的付款嘗試。
使用 ETag
Etag是使更新請求冪等的好方法。ETag 由伺服器根據當前資源表示生成。ETag 在ETag標頭值中返回。例如:
請求:
GET /users/123 |
響應:
HTTP/1.1 200 Ok ETag: "a915ecb02a9136f8cfc0c2c5b2129c4b" { "name": "John Doe", "email": "john@doe.com" } |
現在假設我們要使用JSON Merge Patch請求來更新使用者名稱:
PATCH /users/123 If-Match: "a915ecb02a9136f8cfc0c2c5b2129c4b" { "name": "John Smith" } |
我們使用If-Match條件告訴伺服器僅在 ETag 匹配時才執行請求。更新資源會導致伺服器端更新 ETag。因此,如果請求被意外傳送兩次,伺服器會拒絕第二次請求,因為 ETag 不再匹配。在這種情況下,通常應該返回 HTTP 412(前提條件失敗)。
顯然 ETags 只能在資源已經存在的情況下使用。所以這個解決方案不能用於在建立資源時確保冪等性。從好的方面來說,這是一種標準化且易於理解的方式。
使用單獨的冪等鍵
另一種方法是使用單獨的客戶端生成的金鑰來提供冪等性。透過這種方式,客戶端生成一個金鑰並使用自定義標頭(例如Idempotency-Key)將其新增到請求中。
例如,建立新使用者的請求可能如下所示:
POST /users Idempotency-Key: 1063ef6e-267b-48fc-b874-dcf1e861a49d { "name": "John Doe", "email": "john@doe.com" } |
現在伺服器可以保留冪等金鑰Idempotency-Key並拒絕使用相同金鑰的任何進一步請求。
使用這種方法有兩個問題需要考慮:
- 如何處理尚未成功完成的請求(例如透過返回 HTTP 4xx 或 5xx 狀態程式碼)?在這些情況下,伺服器是否應該儲存冪等金鑰?如果是這樣,客戶端如果想重試請求,總是需要使用新的冪等金鑰。
- 如果伺服器使用已知冪等鍵檢索請求,返回什麼。
我個人傾向於僅在請求成功完成時才儲存冪等鍵。在第二種情況下,我將返回 HTTP 409(衝突)以指示已經執行了具有給定冪等鍵的請求。
但是,這裡的意見可能會有所不同。例如,Stripe API 使用 Idempotency-Key 標頭。Stripe 在所有情況下都儲存冪等鍵和返回的響應。如果提供的冪等鍵已經存在,則無需再次執行操作即可返回儲存的響應。
在我看來,後者可能會使客戶感到困惑。另一方面,它為客戶端提供了再次檢索先前執行的請求的響應的選項。
概括
一個簡單的唯一業務金鑰可用於為建立資源的操作提供冪等性。
對於非建立操作,我們可以將伺服器生成的 ETag 與If-Match標頭結合使用。這種方法具有標準化和廣為人知的優點。
作為替代方案,我們可以使用自定義請求標頭中提供的客戶端生成的冪等性金鑰。伺服器儲存那些冪等金鑰並拒絕包含已使用冪等金鑰的請求。這種方法可用於所有型別的請求。但是,它不是標準化的,有一些需要考慮的地方。
相關文章
- 使用冪等性抑制API服務中的重複請求 - tkareineAPI
- 前端如何防止介面重複提交前端
- Java中的請求冪等性處理:如何確保服務端的操作重複安全Java服務端
- SpringBoot如何防止重複提交?- Adrian AdendrataSpring Boot
- 架構設計 | 介面冪等性原則,防重複提交Token管理架構
- js 防止重複提交方案JS
- PHP 防止表單重複提交PHP
- 如何防止使用者重複提交訂單?(上)
- 如何防止使用者重複提交訂單?(下)
- 如何防止使用者重複提交訂單?(中)
- HTTP有哪些保證冪等性和安全性的方法? - mscharhagHTTP
- Struts2防止表單重複提交
- 前端防止使用者重複提交-js前端JS
- iOS 使用form表單形式提交post請求iOSORM
- vue帶參請求,登入時效(防止重複登陸)Vue
- gRPC重試與介面冪等性RPC
- PHP防止使用者重複提交表單PHP
- 介面請求 (get、post、head 等) 詳解
- 介面請求(get、post、head等)詳解
- SpringBoot自定義註解+AOP+redis實現防介面冪等性重複提交,從概念到實戰Spring BootRedis
- SpringMVC中如何傳送GET請求、POST請求、PUT請求、DELETE請求。SpringMVCdelete
- POST 請求的三種常見資料提交格式
- uniapp之post請求如何用APP
- 技術分享:如何避免ajax重複請求?
- 介面冪等性如何實現?
- 使用axios post 請求資料無法提交的問題iOS
- java post 請求Java
- [java]如何裂解RESTful的冪等性JavaREST
- 如何保證介面的冪等性?
- Rabbitmq消費者冪等性(不重複消費)MQ
- 日常Bug排查-Nginx重複請求?Nginx
- HTTP呼叫超時咋辦?重複請求又如何?HTTP
- 【Java面試】什麼是冪等?如何解決冪等性問題?Java面試
- WinForm MDIParent如何防止重複開啟ORM
- post 請求工具類
- 如何使用post請求下載檔案
- 如何在Camel中Post一個請求?
- 冪等性問題