עודכן לפני חודש
שלחת בקשה. חלף פסק הזמן. האם השרת עיבד אותה?
אתה באמת לא יודע. הבקשה אולי הגיעה והצליחה, רק התגובה אבדה. או שהבקשה מתה בדרך. הרשת לא אומרת לך אם הבקשה שלך הצליחה — היא אומרת לך אם קיבלת תשובה. אלה לא אותו דבר.
אידמפוטנטיות היא האופן שבו מתמודדים עם אי-ודאות זו.
מה פירוש אידמפוטנטיות
שיטת HTTP היא אידמפוטנטית אם ביצוע אותה בקשה מספר פעמים מייצר את אותה השפעה על השרת כמו ביצועה פעם אחת.
DELETE היא אידמפוטנטית. מחק משאב פעם אחת — הוא נעלם. מחק אותו עשר פעמים נוספות — הוא עדיין נעלם. התגובות שונות (הראשונה מחזירה 204 No Content, שאר מחזירות 404 Not Found), אבל התוצאה זהה: המשאב לא קיים.
POST בדרך כלל אינה אידמפוטנטית. שלח טופס שלוש פעמים — ייתכן שתיצור שלושה משאבים. חייב כרטיס אשראי שלוש פעמים — תחייב את הלקוח שלוש פעמים. כל בקשה משנה את מצב השרת בצורה חדשה.
השיטות האידמפוטנטיות
GET
אחזור משאב אינו משנה אותו. בקש את אותו מאמר מאה פעמים — מצב השרת נשאר ללא שינוי.
הערה: ממשקי API בעיצוב לקוי מוסיפים תופעות לוואי ל-GET — הגדלת מוני צפיות, הפעלת פעולות, כתיבת לוגים. זה מפר את מפרט HTTP ויוצר בעיות אמיתיות כאשר פרוקסים, דפדפנים ומאזני עומס מנסים שוב בקשות GET, בהנחה שהן בטוחות לחזרה.
PUT
עדכון משאב למצב מסוים הוא אידמפוטנטי. הגדר את כותרת המאמר ל-"Updated Title" פעם אחת — יש לו את הכותרת הזו. הגדר שוב — עדיין יש לו את הכותרת הזו.
DELETE
הסרת משאב היא אידמפוטנטית. המשאב נעלם לאחר הבקשה הראשונה. הוא עדיין נעלם לאחר העשירית.
HEAD ו-OPTIONS
HEAD מאחזר מטא-נתונים מבלי לשנות דבר. OPTIONS שואל אילו פעולות נתמכות. אף אחד מהם אינו משנה את מצב השרת.
השיטות הלא-אידמפוטנטיות
POST
כל POST עשוי ליצור מצב חדש:
זוהי בעיית ההגשה הכפולה. פסקי זמן ברשת, משתמשים חסרי סבלנות שלוחצים על "שלח" כמה פעמים, ניסיונות חוזרים אוטומטיים — כולם עלולים ליצור כפילויות לא מכוונות.
PATCH
PATCH יכולה ללכת בשני הכיוונים, תלוי בפורמט ה-patch.
אידמפוטנטית (הגדרת ערכים מוחלטים):
לא-אידמפוטנטית (שינויים יחסיים):
JSON Merge Patch (RFC 7396) היא אידמפוטנטית. JSON Patch (RFC 6902) עשויה להיות לא-אידמפוטנטית, תלוי בפעולות.
למה זה חשוב
ניסיונות חוזרים בטוחים
עם שיטות אידמפוטנטיות, אפשר לנסות שוב בחופשיות:
GET היא אידמפוטנטית. ניסיון חוזר לא יגרום נזק.
עם POST, ניסיון חוזר הוא מסוכן:
מאזני עומס מנסים שוב אוטומטית
כאשר שרת backend אינו מגיב, מאזני עומס מנסים שוב בקשות אידמפוטנטיות על שרת אחר:
הם לא מנסים שוב POST ללא הגדרה מפורשת. הם יודעים שזה מסוכן.
דפדפנים מגנים על משתמשים
רענן דף לאחר הגשת טופס ותראה:
דפדפנים יודעים ש-POST אינה אידמפוטנטית. הם מזהירים לפני חזרה על הפעולה.
מטמון עובד
רק שיטות אידמפוטנטיות יכולות להישמר במטמון בבטחה. אם בקשה משנה את מצב השרת, תגובות מהמטמון הופכות לשקר.
תגובות GET נשמרות במטמון כברירת מחדל. תגובות POST לא.
הפיכת POST לאידמפוטנטית
מכיוון ש-POST לעתים קרובות זקוקה לניסיונות חוזרים, מספר דפוסים מאפשרים להוסיף לה אידמפוטנטיות:
מפתחות אידמפוטנטיות
הלקוח מייצר מפתח ייחודי לכל פעולה לוגית:
השרת עוקב אחרי המפתחות. אותו מפתח פעמיים? מחזיר את התוצאה המקורית:
כעת ניסיונות חוזרים בטוחים.
מזהים שנוצרים על ידי הלקוח
תן ללקוח לספק את המזהה:
PUT לכתובת URL מסוימת היא אידמפוטנטית. הזמנה קיימת? עדכן אותה. לא קיימת? צור אותה. ניסיון חוזר מייצר את אותה הזמנה בדיוק.
אסימונים חד-פעמיים
הטמן אסימון בטופס:
השרת מאמת ומבטל את האסימון:
הגשות כפולות נכשלות.
עיצוב RESTful
השתמש בשיטות לפי הסמנטיקה שלהן:
פעולות אידמפוטנטיות ← PUT או DELETE
- הגדרת משאב למצב מסוים: PUT
- הסרת משאב: DELETE
פעולות לא-אידמפוטנטיות ← POST
- יצירה עם מזהים שנוצרים על ידי השרת: POST
- פעולות שאין לחזור עליהן: POST
אידמפוטנטי. הגדרת הסטטוס ל-"active" עשר פעמים משאירה אותו פעיל.
לא אידמפוטנטי. שליחה פעמיים שולחת שתי הודעות.
בדיקת אידמפוטנטיות
ודא שהשיטות האידמפוטנטיות שלך אכן מתנהגות כך:
טעויות נפוצות
GET עם תופעות לוואי: אל תשנה מצב בטיפולי GET. פרוקסים ודפדפנים ינסו שוב בקשות GET ללא אישור.
ניסיון חוזר עיוור של POST: ללא מפתחות אידמפוטנטיות או אסימונים, ניסיונות חוזרים יוצרים כפילויות.
הנחה ש-PATCH היא אידמפוטנטית: זה תלוי בפורמט ה-patch. פעולות הגדלה אינן אידמפוטנטיות.
שאלות נפוצות על אידמפוטנטיות של שיטות HTTP
מדוע DELETE מחזירה 404 בבקשות עוקבות אם היא אידמפוטנטית?
אידמפוטנטיות מתייחסת להשפעה על השרת, לא לתגובה. לאחר DELETE, המשאב לא קיים — בין אם מחקת אותו פעם אחת ובין אם עשר פעמים. ה-404 פשוט אומר "הוא לא כאן," וזה בדיוק המצב שרצית להגיע אליו. ההשפעה זהה; רק קוד התגובה שונה.
האם אני יכול לנסות שוב בבטחה כל בקשה שפג פסק הזמן שלה?
רק בקשות אידמפוטנטיות (GET, PUT, DELETE, HEAD, OPTIONS). עבור POST, תזדקק למפתחות אידמפוטנטיות או להגנה דומה. בלעדיהן, ניסיון חוזר של POST שפג פסק הזמן שלה עלול ליצור כפילויות — אינך יודע אם הבקשה המקורית הצליחה.
מה ההבדל בין שיטות אידמפוטנטיות לשיטות בטוחות?
שיטות בטוחות (GET, HEAD, OPTIONS) אינן משנות את מצב השרת כלל. שיטות אידמפוטנטיות עשויות לשנות מצב, אבל חזרה עליהן אינה משנה את התוצאה. DELETE היא אידמפוטנטית אך אינה בטוחה — היא משנה מצב, אבל ביצועה פעמיים יש את אותה השפעה כמו ביצועה פעם אחת.
כמה זמן כדאי לשמור מפתחות אידמפוטנטיות?
מספיק זמן כדי לאפשר ניסיונות חוזרים ולפצות על עיכובי רשת — בדרך כלל בין שעה ל-24 שעות, בהתאם לשימוש. Stripe משתמשת ב-24 שעות. עבור רוב ממשקי ה-API, מספר שעות מספיקות. זמן קצר מדי ועלולים ניסיונות חוזרים לחמוק; זמן ארוך מדי מבזבז שטח אחסון.
האם דף זה היה מועיל?