במסמך הזה מוסבר איך ממשקי API של Google פועלים עם גרסאות שונות של HTTP ועם הטמעות שונות. אם אתם משתמשים בספריות לקוח שיצרנו או שיצרתם בעצמכם (הגישה המומלצת לרוב תרחישי השימוש), אתם לא צריכים לדאוג לגבי הפרטים האלה. הספריות מטפלות אוטומטית בתקשורת ברמה הנמוכה עם השרת.
אם אתם מפתחים מנוסים שכותבים קוד מותאם אישית כדי לגשת לממשק REST של API באמצעות צד לקוח HTTP של צד שלישי, כדאי שתבינו את המושגים הרלוונטיים שמתועדים כאן, וגם את התכונות שמסופקות על ידי ספריית ה-HTTP שבחרתם.
עבודה עם פרוטוקולים קוויים (HTTP/*)
בקטע הזה מתוארים פרוטוקולי התקשורת הנתמכים (בדרך כלל גרסה של HTTP) ש-Google APIs יכולים להשתמש בהם כדי לתקשר בין לקוחות לשרתים, ומוסבר איך מומלץ להשתמש בהם.
סמנטיקה של HTTP
כשמפתחים קוד של לקוח API, צריך לפעול לפי הסמנטיקה של פרוטוקול HTTP. יכול להיות ששרתי Proxy בצד השרת או מחסני API יתמכו רק בחלק מהתכונות הסטנדרטיות של HTTP, ויכול להיות שהם יתמכו גם בגרסאות שלהם שתואמות לאחור.
הסמנטיקה של פרוטוקול HTTP שצריך לטפל בה בהטמעות של ממשקי API בצד השרת נשלטת על ידי מחסנית השרת. כדאי להסתמך על סמנטיקה כזו רק אם התכונות האלה מתועדות באופן מפורש כחלק ממפרט ה-API, כמו תמיכה במטמון.
גרסאות HTTP
לקוחות יכולים להשתמש בכל פרוטוקול HTTP/* , בהתאם להרשאה שניתנה על ידי פלטפורמת הלקוח או הרשת בצד הלקוח, או בהתאם למה שסוכם עם ה-proxy בצד השרת. בין הפרוטוקולים הנתמכים: HTTP/1.1, HTTP/2 ו-HTTP/3 (QUIC). לא מומלץ להשתמש בתמיכה מדור קודם ב-HTTP/1.0.
יכול להיות שחלק מהתכונות של ה-API נתמכות רק בגרסאות חדשות יותר של פרוטוקולי HTTP. חלק מהתכונות מפורטות באופן מלא רק ב-HTTP/2 וב-HTTP/3, כמו סטרימינג מרובה ערוצים דו-כיווני. חשוב להכיר את המגבלות של גרסאות שונות של HTTP אם אתם צריכים להשתמש באחת מהתכונות האלה כחלק ממפרט ה-API. שימו לב שתכונות ישנות יותר כמו HTTP/2 Server Push הוצאו משימוש ולא נתמכות על ידי לקוחות אינטרנט מודרניים.
באופן כללי, אנחנו ממליצים להשתמש ב-HTTP/3 או ב-HTTP/2 כדי לשפר את הביצועים, לצמצם את חסימת הראש של התור ולשפר את העמידות בפני כשלים ברשת.
ערוצים
המונח 'ערוצים' מתייחס לחיבורי רשת בשכבה 4, שהם בדרך כלל שקעי TCP עבור HTTP/1.1 ו-HTTP/2, ושקעי UDP עבור HTTP/3 (QUIC). אפליקציות לקוח לא צריכות להניח הנחות לגבי אופן הניהול של הערוצים מקצה לקצה, כי החיבורים כמעט תמיד מסתיימים על ידי שרתי proxy של ממשק הקצה של Google (GFE) בשם תהליך השרת.
לקוחות HTTP/1.1: אם משתמשים ב-HTTP/1.1, תמיד צריך לעשות שימוש חוזר בחיבורי TCP (Connection: Keep-Alive). ספריות לקוח של HTTP בדרך כלל מנהלות מאגר חיבורים כדי לאפשר שימוש חוזר. מומלץ להימנע מצינורות HTTP בחיבורי HTTP/1.1. התמיכה בהם מוגבלת והם עלולים לגרום לבעיות. מידע נוסף זמין במאמר בנושא HTTP ו-TCP.
לקוחות HTTP/2 ו-HTTP/3: לקוחות ודפדפנים מודרניים משתמשים בעיקר ב-HTTP/2 או ב-HTTP/3. שני הפרוטוקולים תומכים בריבוב, ומאפשרים לשלוח כמה בקשות ותשובות בו-זמנית דרך חיבור יחיד.
- HTTP/2 – משתמש בחיבור TCP יחיד לכל מקור.
- HTTP/3 – משתמש בחיבור QUIC יחיד דרך UDP לכל מקור. פרוטוקול QUIC משלב הצפנת TLS, בקרת עומס וניהול חיבורים, ולכן הוא מספק יתרונות כמו הגדרת חיבור מהירה יותר (0-RTT או 1-RTT) וחסינות לחסימת ראש התור של TCP בסטרימינג.
עם HTTP/2 ו-HTTP/3, מגבלות הדפדפן על מספר חיבורי ה-TCP המקבילים למארח יחיד (לדוגמה, 2-10) כבר לא מהוות בעיה משמעותית בביצועים. עם זאת, חשוב לדעת ששרתים (או שרתי proxy כמו GFE) עדיין יכולים לאכוף מגבלות על המספר המקסימלי של סטרימינג בו-זמני בחיבור יחיד מסוג HTTP/2 או HTTP/3. כך נמנע עומס יתר ומובטח שימוש הוגן במשאבים (לדוגמה, על ידי הגבלת מספר הבקשות או הזרמים בו-זמנית לכל חיבור ל-100).
HTTPS
לקוחות יכולים לגשת ל-API באמצעות HTTPS או HTTP, בהתאם למה שנתמך במפרט ה-API. המשא ומתן על TLS וגרסאות ה-TLS שקופים לאפליקציות הלקוח. כברירת מחדל, ממשקי Google API מקבלים רק תעבורת נתונים ב-HTTPS.
פורמטים של בקשות ותגובות
בקטע הזה מתוארת המבנה של אינטראקציות עם ה-API, כולל השימוש בנתונים בקידוד URL, בשיטות HTTP ספציפיות לפעולות RESTful ובפורמטים של מטען ייעודי (payload) מבוססי JSON.
בקשה של כתובות URL
מיפוי JSON-REST תומך בנתוני בקשה שמקודדים בכתובת URL, ובגוף הבקשה והתגובה של HTTP נעשה שימוש ב-application/json בתור Content-Type.
גוף ה-HTTP משתמש במערך JSON כדי לתמוך בשיטות RPC שמועברות בסטרימינג, ומערך ה-JSON עשוי להכיל כל מספר של הודעות JSON או הודעת JSON של סטטוס שגיאה.
כתובות URL ארוכות של בקשות
יש הגבלה מעשית על אורך כתובת ה-URL, שבדרך כלל מוגדרת כברירת מחדל ל-16KB, אבל יכול להיות שהיא תשתנה בהתאם לשרת. אם ה-API שלכם משתמש בבקשות GET עם כתובות URL שאורכן חורג מהאורך הזה, יכול להיות שהבקשות לא יגיעו לשרת ה-API של היעד ויידחו על ידי ממשק הקצה של Google (GFE) עם הודעת השגיאה Your client has issued a malformed or illegal request.
כדי לעקוף את המגבלה, קוד הלקוח צריך להשתמש בבקשת POST עם Content-Type של application/x-www-form-urlencoded יחד עם כותרת ה-HTTP X-HTTP-Method-Override: GET. הגישה הזו פועלת גם עבור בקשות DELETE.
שיטות HTTP (פעלים)
אם כתובות ה-URL של הבקשות פועלות לפי מודל REST, שיטות ה-HTTP שלהן מצוינות כחלק ממפרט ה-API. בפרט, כל method של API חייבת לעמוד בדרישות של פרוטוקול HTTP על סמך פועל ה-HTTP הספציפי שאליו ממופה ה-method של ה-API. מידע נוסף זמין במפרט של Hypertext Transfer Protocol וב-RFC של PATCH Method.
שיטות בטוחות, כמו HTTP GET ו-HEAD, לא אמורות לייצג פעולה אחרת מלבד אחזור. במיוחד, בקשות HTTP GET צריכות להיחשב בטוחות ולא אמורות להיות להן תופעות לוואי שגלויות ללקוח.
אידמפוטנטיות ב-HTTP פירושה שההשפעות של כמה בקשות זהות זהות לאלה של בקשה אחת. GET, PUT ו-DELETE הן שיטות HTTP אידמפוטנטיות שרלוונטיות למדריך הסגנון. חשוב לציין שהאידמפוטנטיות מוגדרת רק במונחים של תופעות לוואי בצד השרת, ולא מציינת דבר לגבי התגובה. בפרט, DELETE למשאבים שלא קיימים צריך להחזיר 404 (Not Found).
השיטות HTTP POST ו-PATCH לא בטוחות ולא אידמפוטנטיות. (השיטה PATCH הוצגה ב-RFC 5789)
| פועל HTTP | בטוח | אידמפוטנטי |
|---|---|---|
GET |
כן | כן |
PUT |
כן | |
DELETE |
כן | |
POST |
||
PATCH |
פורמטים של מטען ייעודי (payload)
הבקשה והתגובה צריכות להיות מאותו סוג תוכן, אלא אם הבקשה היא
GETאוPOSTעם גוף מסוגapplication/x-www-form-urlencoded.יש תמיכה ב-JSON תחת סוג ה-MIME
application/json. המיפוי מ-proto3 ל-JSON מוגדר באופן רשמי במיפוי JSON.אפשר להשתמש בפרמטרים של טופס (
POST) במקום בפרמטרים של שאילתה בכתובת URL (GET), לפי אותו כלל מיפוי בסגנון REST למיפוי שדות של בקשות לפרמטרים של שאילתות. הערך הנתמך שלContent-Typeהואapplication/x-www-form-urlencoded.
סטרימינג
בקטע הזה מוסבר איך Google APIs מטפלים בהזרמת נתונים מהלקוח לשרת ומהשרת ללקוח, ומתייחסים באופן ספציפי למגבלות של תקשורת חד-כיוונית לעומת תקשורת דו-כיוונית, ולדרישות הקידוד של הודעות JSON שמוזרמות.
חצי דופלקס לעומת דופלקס מלא
HTTP הוא פרוטוקול של בקשה ותגובה שמאפשר להעביר את גוף הבקשה או התגובה שלו באמצעות שיטות שונות להעברת נתונים שמתבססות על זרם, כמו TCP (HTTP/1.x) או וריאציות של multiplexing (SPDY, HTTP/2, QUIC).
בתור מפתחים של לקוחות, האפליקציה שלכם יכולה ליצור את גוף הבקשה במצב סטרימינג, כלומר סטרימינג מצד הלקוח. באופן דומה, האפליקציה יכולה גם לצרוך את גוף התשובה במצב סטרימינג, כלומר סטרימינג מהשרת.
עם זאת, במפרט HTTP לא מצוין אם לשרת מותר להזרים בחזרה את תוכן התגובה (למעט תגובות שגיאה) כשהתוכן של הבקשה עדיין בהמתנה. הסמנטיקה הזו נקראת הזרמת נתונים דו-כיוונית. למרות שתוכנות רבות של HTTP client/server/proxy מאפשרות סטרימינג דו-כיווני מלא, גם עבור HTTP/1.1, כדי למנוע בעיות תאימות, ממשקי API מבוססי-HTTP בענן מוגבלים לסטרימינג חד-כיווני בלבד.
כברירת מחדל, שיטות סטרימינג דו-כיווניות בממשקי Cloud API מניחות סמנטיקה של דופלקס מלא. כלומר, לא בטוח להשתמש ב-HTTP כדי להפעיל שיטה כזו. אם שיטת סטרימינג היא רק חצי דופלקס (כפי שנאכף על ידי השרת), מסמך ה-API צריך לציין בבירור את התנהגות חצי הדופלקס.
במקרה של לקוחות דפדפן, הסמנטיקה הרגילה של HTTP מוגבלת עוד יותר על ידי ממשקי ה-API של הרשת בדפדפן. דפדפנים תומכים בהזרמת נתונים מהשרת (שבדרך כלל מתבצעת בהתאם למסגור ברמת התעבורה) באמצעות XHR או Fetch. Fetch API משתמש בwhatwg streams.
בגלל הגבלות בדפדפן, ממשקי Cloud API שנדרשת להם תמיכה בדפדפן צריכים להימנע מהזרמת לקוח ומהזרמה דו-כיוונית, או לספק API נפרד במיוחד ללקוחות דפדפן.
באופן כללי, סטרימינג מהלקוח דרך האינטרנט פחות שימושי מסטרימינג מהשרת. הסיבה לכך היא ששימוש בסטרימינג בצד הלקוח מוביל לעיתים קרובות לשירות עם שמירת מצב, מה שמשפיע לרעה על איזון העומסים והופך את המערכת לפגיעה יותר לכשלים או להתקפות. לעומת זאת, סטרימינג מהשרת יכול להיות שימושי כי הוא יכול לצמצם באופן משמעותי את זמן האחזור ברשתות עם עיכובים ארוכים של RTT.
קידוד הודעות
הודעות JSON בסטרימינג מקודדות כמערך של הודעות JSON. גוף הבקשה או התגובה יישארו כסוג MIME תקין של JSON.
דוגמה לקידוד של עדכון תוכן של לקוח:
1 <length> <message-bytes> 1 <length> <message-bytes> … EOF
דוגמה לקידוד של סטרימינג בשרת:
1 <length> <message-bytes> … 2 <length> <status-bytes> EOF
קידוד ברמת החוט: ההגדרה של StreamBody משמעותית רק בהקצאה של מזהי תגים לשדות messages ו-status <length> שיקודדו ב-varint עם 1-2 בייטים להודעות רגילות, כך שהתקורה הכוללת של הקידוד היא 2-3 בייטים לכל הודעה.
כדי לתמוך בזרמים בקידוד base64, צריך להוסיף שדה אופציונלי של ריפוד:
message StreamBody {
repeated bytes message = 1;
google.rpc.Status status = 2;
repeated bytes padding = 15; // max one-byte tag-id: xxx01111
}
צריך לצרף את הודעות השגיאה כרכיב האחרון במערך JSON או protobuf, באותו פורמט של הודעות רגילות.
ניהול מצב
התנהגות של סגירה חלקית מוגדרת היטב בכל גרסה של HTTP עבור לקוח או שרת, כדי לסמן לצד השני שהגוף הושלם.
בפרט, קוד הלקוח יכול להשלים את הבקשה בזמן שהוא עדיין ממתין לתגובה. באופן דומה, יכול להיות שהלקוח יראה תגובה שהושלמה בזמן שגוף הבקשה עדיין נכתב בשרת. תקן ה-HTTP מצפה מהלקוח לבטל או להשלים את הבקשה כשהתגובה הושלמה בצורה לא צפויה, בדרך כלל עם סטטוס שגיאה. כלומר, בתנאים רגילים השרת לא אמור להשלים תגובה בזמן שהלקוח עדיין שולח את הבקשה.
ביטול
תמיכה בביטול מאפשרת ללקוח לבטל בקשה כשהבקשה או התגובה עדיין בהמתנה.
אין תמיכה אמינה בביטול של לקוחות HTTP/1.*, כי לקוח יכול לסגור חיבור TCP אחרי שהבקשה הושלמה בלי לבטל את הבקשה או את עסקת התגובה. TCP FIN, ב-HTTP/1.1, לא אמור להתפרש כביטול, גם אם החיבור מסומן כחיבור פעיל (Connection: Keep-Alive).
עם זאת, אחרי שהלקוח סוגר את חיבור ה-TCP, אם השרת מנסה לכתוב נתונים ללקוח, נוצרת בקשת RST, שיכולה להפעיל ביטול.
חשוב לזכור שביטול הוא בעיה גם בממשקי API שאינם סטרימינג. זה קורה במיוחד כשהתשובה כוללת שאילתת Long Polling, ולכן יכול להיות שהחיבור יישאר במצב לא פעיל למשך תקופה ממושכת.
ביטול מפורש נתמך ב-SPDY, HTTP/2 ו-QUIC, במיוחד בהודעת go-away.
Keep-alive
תמיכה ב-Keep-alive מאפשרת ללקוח או לשרת לזהות עמית שנכשל, גם במקרה של אובדן מנות או כשלים ברשת.
אין תמיכה בהודעת keep-alive ב-HTTP/1.1 כי הודעת TCP keep-alive היא לא גישה מעשית.
פרוטוקול QUIC או HTTP/2 מציעים הודעות בקרה מיוחדות לצורך הטמעה של תמיכה בהודעת keep-alive באפליקציות, כולל דפדפנים.
עם זאת, כדי להבטיח את הפעולה של הודעת keep-alive ואת זיהוי הכשלים, סביר להניח שתצטרכו ספריית לקוח עם תמיכה נדרשת בצד השרת. הזרמת נתונים לטווח ארוך באינטרנט נוטה להיות בעייתית כשמסתמכים על HTTP בסיסי כפרוטוקול התקשורת.
בקרה על זרימת נתונים
כדי לתמוך בבקרת זרימה, הלקוח צריך להפיץ אירועים של בקרת זרימה ברמת התעבורה לאפליקציית הלקוח. המנגנון בפועל תלוי בסגנון של ה-API של לקוח ה-HTTP שבו משתמשת אפליקציית הלקוח. לדוגמה, כדי למנוע עומס יתר על הלקוח או על השרת, צריך לחסום פעולות כתיבה וקריאה, או לא לחסום פעולות קריאה וכתיבה עם תמיכה מפורשת בבקרה על זרימת נתונים, כדי שהאפליקציות יוכלו לטפל באירועים של בקרה על זרימת נתונים ולפעול בהתאם להם.
פרוטוקול HTTP/1.1 מסתמך על בקרת זרימה של TCP.
ל-SPDY ול-HTTP/2 יש בקרה על זרימת נתונים משלהן ברמת הזרם, שנתונה לבקרה על זרימת נתונים של TCP ברמת החיבור, כי הבקשות מרובות-משתתפים על פני חיבור TCP יחיד.
פרוטוקול QUIC פועל על UDP ולכן הוא מנהל את בקרה על זרימת נתונים באופן עצמאי לחלוטין.