~/کدولاگ
→ همه‌ی مقاله‌ها

کلیدهای Idempotency، به زبان ساده

چرا درخواست‌های POST روی شبکه‌های ناپایدار خطرناک‌اند، و چطور یک هدر ساده شما را از دوبار شارژ کردن مشتری نجات می‌دهد.

طراحی-apiپایداریhttp

تلاش مجدد (retry) یک واقعیت زندگی در اینترنت است. یک کلاینت POST /payments می‌فرستد، شبکه دچار مشکل می‌شود، و کلاینت — که هیچ ایده‌ای ندارد سرور درخواست را دریافت کرده یا نه — دوباره تلاش می‌کند. بدون محافظت، همین‌الان دوبار از کسی پول کشیده‌اید.

ایده‌ی اصلی

یک کلید idempotency یک توکن یکتاست که کلاینت تولید می‌کند و همراه یک درخواستِ تغییردهنده می‌فرستد. سرور این کلید را به همراه نتیجه‌ی اولین اجرای موفق ذخیره می‌کند. اگر همان کلید دوباره ظاهر شود، سرور به‌جای انجام دوباره‌ی کار، نتیجه‌ی ذخیره‌شده را برمی‌گرداند.

POST /payments HTTP/1.1
Idempotency-Key: 9f8c2b1a-6d4e-4f2a-9c3b-1e2d3f4a5b6c
Content-Type: application/json

{ "amount": 4200, "currency": "usd" }

ذخیره‌ی کلید

به ازای هر کلید به سه چیز نیاز دارید: خودِ کلید، یک اثرانگشت از بدنه‌ی درخواست، و پاسخی که برگرداندید.

اگر یک کلید با بدنه‌ای متفاوت دوباره استفاده شود، این یک باگ سمت کلاینت است — به‌جای بازگرداندن خاموشِ نتیجه‌ی قدیمی، آن را با 422 Unprocessable Entity رد کنید.

نکاتی که باید مراقبشان باشید

  • به کلیدها یک TTL بدهید. نمی‌خواهید برای همیشه زنده بمانند.
  • کلیدها را به ازای هر endpoint و هر کاربر محدود کنید.
  • مسابقه‌ای (race) را مدیریت کنید که دو درخواست یکسان هم‌زمان می‌رسند — یک محدودیت یکتایی (unique constraint) روی ستون کلید دوست شماست.

این کار را یک‌بار، به‌صورت متمرکز، انجام دهید و هر endpoint ناامنِ سرویس‌تان رایگان صاحب تلاش‌های مجدد امن می‌شود.