שימוש ב-WebTransport

WebTransport הוא ממשק API שמציע העברת הודעות דו-כיוונית בזמן אחזור קצר בין לקוח לשרת. מידע נוסף על תרחישים לדוגמה ועל שליחת משוב לגבי העתיד של ההטמעה.

רקע

מהו WebTransport?

WebTransport הוא ממשק API לאינטרנט שמשתמש בפרוטוקול HTTP/3 ככלי להעברה דו-כיוונית. הוא מיועד לתקשורת דו-כיוונית בין לקוח אינטרנט לשרת HTTP/3. הוא תומך בשליחת נתונים באופן לא מהימן באמצעות ממשקי ה-API של חבילות הנתונים, וגם באופן מהימן באמצעות ממשקי ה-API של הזרמים.

דאגרמות הן אידיאליות לשליחה ולקבלה של נתונים שלא נדרשות להם הבטחות חזקות לגבי העברה. הגודל של חבילות נתונים ספציפיות מוגבל על ידי יחידת ההעברה המקסימלית (MTU) של החיבור הבסיסי, והן עשויות להועברו בהצלחה או לא. אם הן מועברות, הן עשויות להגיע בסדר שרירותי. המאפיינים האלה הופכים את ממשקי ה-API של חבילות הנתונים למתאימים במיוחד להעברת נתונים עם זמן אחזור קצר, לפי יכולת המערכת. אפשר לחשוב על חבילות נתונים כהודעות User Datagram Protocol‏ (UDP), אבל מוצפנות ומנוהלות לפי עומס.

לעומת זאת, ממשקי ה-API של הזרמים מספקים העברת נתונים מהימנה ומסודרת. הם מתאימים לתרחישים שבהם צריך לשלוח או לקבל מקור נתונים אחד או יותר של נתונים מסודרים. השימוש בכמה מקורות נתונים של WebTransport דומה ליצירת כמה חיבורי TCP, אבל מאחר ש-HTTP/3 משתמש בפרוטוקול QUIC קל יותר, אפשר לפתוח ולסגור אותם בלי הרבה תקורה.

תרחישים לדוגמה

זוהי רשימה קטנה של דרכים אפשריות שבהן מפתחים יכולים להשתמש ב-WebTransport.

  • שליחת מצב המשחק במרווחי זמן קבועים עם זמן אחזור מינימלי לשרת באמצעות הודעות קטנות, לא מהימנות ולא בסדר.
  • קבלת מקורות מדיה שנשלחים מהשרת עם זמן אחזור מינימלי, ללא קשר למקורות נתונים אחרים.
  • קבלת התראות שנשלחות מהשרת בזמן שדף אינטרנט פתוח.

נשמח לשמוע מכם איך אתם מתכננים להשתמש ב-WebTransport.

תמיכה בדפדפנים

תמיכה בדפדפנים

  • Chrome: ‏ 97.
  • Edge: ‏ 97.
  • Firefox: ‏ 114.
  • Safari: לא נתמך.

מקור

כמו בכל התכונות שאין להן תמיכה אוניברסלית בדפדפנים, מומלץ לכתוב קוד באופן הגנתי באמצעות זיהוי תכונות.

הסטטוס הנוכחי

שלב סטטוס
1. יצירת הסבר הושלם
2. יצירת טיוטה ראשונית של המפרט הושלם
3. איך אוספים משוב ומבצעים שיפורים בעיצוב הושלם
4. גרסת מקור לניסיון הושלם
5. השקה Chromium 97

הקשר של WebTransport לטכנולוגיות אחרות

האם WebTransport מחליף את WebSockets?

אולי. יש תרחישים לדוגמה שבהם WebSockets או WebTransport עשויים להיות פרוטוקולי תקשורת תקפים לשימוש.

תקשורת ב-WebSockets מבוססת על מקור הודעות יחיד, מהימן ומסודר, שמתאים לסוגים מסוימים של צורכי תקשורת. אם אתם זקוקים למאפיינים האלה, ממשקי ה-API של WebTransport לסטרימינג יכולים לספק אותם גם כן. לעומת זאת, ממשקי ה-API של חבילות הנתונים של WebTransport מספקים העברה עם זמן אחזור קצר, ללא הבטחות לגבי מהימנות או סדר, ולכן הם לא תחליף ישיר ל-WebSockets.

כשמשתמשים ב-WebTransport דרך ממשקי ה-API של חבילות הנתונים או דרך כמה מכונות Streams API בו-זמנית, אין צורך לדאוג לחסימת ראש התור, שיכולה להיות בעיה ב-WebSockets. בנוסף, יש יתרונות בביצועים כשמקשרים חיבורים חדשים, כי לחיצת היד של QUIC הבסיסית מהירה יותר מהפעלת TCP על גבי TLS.

WebTransport הוא חלק מתכנון חדש, ולכן סביבת WebSocket סביב ספריות הלקוח והשרת חזקה הרבה יותר כרגע. אם אתם צריכים משהו שפועל 'מחוץ לקופסה' עם הגדרות שרת נפוצות, ועם תמיכה רחבה בלקוחות אינטרנט, WebSockets היא האפשרות הטובה ביותר כרגע.

האם WebTransport זהה ל-UDP Socket API?

לא. WebTransport הוא לא UDP Socket API. ב-WebTransport נעשה שימוש ב-HTTP/3, שבתורו משתמש ב-UDP "מתחת למכסה המנוע", אבל ל-WebTransport יש דרישות לגבי הצפנה ובקרת עומסים, שגורמות לו להיות יותר מ-UDP Socket API בסיסי.

האם WebTransport הוא חלופה לצינורות הנתונים של WebRTC?

כן, לחיבורים בין שרתים ללקוחות. ל-WebTransport יש הרבה מאפיינים משותפים לערוצי נתונים של WebRTC, אבל הפרוטוקולים הבסיסיים שונים.

באופן כללי, הפעלת שרת תואם ל-HTTP/3 דורשת פחות הגדרות והגדרות מאשר תחזוקה של שרת WebRTC, שדורשת הבנה של כמה פרוטוקולים (ICE,‏ DTLS ו-SCTP) כדי לקבל תעבורה תקינה. ב-WebRTC יש הרבה יותר רכיבים נעים שיכולים להוביל לכישלון של משא ומתן בין לקוח לשרת.

WebTransport API תוכנן תוך התמקדות בתרחישי השימוש של מפתחי האינטרנט, והוא אמור להרגיש כמו כתיבת קוד מודרני בפלטפורמת אינטרנט, ולא כמו שימוש בממשקי נתוני הערוץ של WebRTC. בניגוד ל-WebRTC, WebTransport נתמך ב-Web Workers, שמאפשר לבצע תקשורת בין שרת ללקוח ללא קשר לדף HTML נתון. מכיוון ש-WebTransport חושף ממשק תואם ל-Streams, הוא תומך באופטימיזציות שקשורות ללחץ חזרה.

עם זאת, אם כבר יש לכם הגדרה עובדת של לקוח/שרת WebRTC שאתם מרוצים ממנה, יכול להיות שהמעבר ל-WebTransport לא יציע יתרונות רבים.

רוצה לנסות?

הדרך הטובה ביותר להתנסות ב-WebTransport היא להפעיל שרת HTTP/3 תואם. לאחר מכן תוכלו להשתמש בדף הזה עם לקוח JavaScript בסיסי כדי לנסות תקשורת בין לקוח לשרת.

בנוסף, יש שרת הדהוד שמנוהל על ידי הקהילה בכתובת webtransport.day.

שימוש ב-API

WebTransport תוכנן על גבי רכיבים בסיסיים מודרניים של פלטפורמת האינטרנט, כמו Streams API. הוא מסתמך במידה רבה על הבטחות, ופועל היטב עם async ו-await.

ההטמעה הנוכחית של WebTransport ב-Chromium תומכת בשלושה סוגים שונים של תעבורת נתונים: חבילות נתונים (datagrams), וגם בשידורים חד-כיווניים ושני-כיווניים.

חיבור לשרת

כדי להתחבר לשרת HTTP/3, יוצרים מכונה של WebTransport. הסכימה של כתובת ה-URL צריכה להיות https. צריך לציין את מספר היציאה באופן מפורש.

צריך להשתמש בהבטחה ready כדי להמתין עד שהחיבור יושלם. ההבטחה הזו לא תתבצע עד להשלמת ההגדרה, והיא תידחה אם החיבור נכשל בשלב QUIC/TLS.

ההבטחה closed מתמלאת כשהחיבור נסגר באופן תקין, ודוחית אם הסגירה הייתה לא צפויה.

אם השרת דוחה את החיבור בגלל שגיאה בהנחיה של הלקוח (למשל, הנתיב של כתובת ה-URL לא תקין), הדבר גורם לדחייה של closed, בעוד ש-ready נשאר ללא פתרון.

const url = 'https://example.com:4999/foo/bar';
const transport = new WebTransport(url);

// Optionally, set up functions to respond to
// the connection closing:
transport.closed.then(() => {
  console.log(`The HTTP/3 connection to ${url} closed gracefully.`);
}).catch((error) => {
  console.error(`The HTTP/3 connection to ${url} closed due to ${error}.`);
});

// Once .ready fulfills, the connection can be used.
await transport.ready;

ממשקי Datagram API

אחרי שיוצרים מכונה של WebTransport שמחוברת לשרת, אפשר להשתמש בה כדי לשלוח ולקבל קטעי נתונים נפרדים שנקראים datagrams.

פונקציית ה-getter של writeable מחזירה WritableStream, שלקוח אינטרנט יכול להשתמש בה כדי לשלוח נתונים לשרת. הפונקציה readable מחזירה ReadableStream, שמאפשרת להאזין לנתונים מהשרת. שני הזרמים לא מהימנים מטבעם, כך שיכול להיות שהנתונים שתכתבו לא יתקבלו על ידי השרת, ולהפך.

בשני סוגי הסטרימינג נעשה שימוש במכונות Uint8Array להעברת נתונים.

// Send two datagrams to the server.
const writer = transport.datagrams.writable.getWriter();
const data1 = new Uint8Array([65, 66, 67]);
const data2 = new Uint8Array([68, 69, 70]);
writer.write(data1);
writer.write(data2);

// Read datagrams from the server.
const reader = transport.datagrams.readable.getReader();
while (true) {
  const {value, done} = await reader.read();
  if (done) {
    break;
  }
  // value is a Uint8Array.
  console.log(value);
}

ממשקי API של Streams

אחרי שתתחברו לשרת, תוכלו גם להשתמש ב-WebTransport כדי לשלוח ולקבל נתונים דרך ממשקי ה-API של Streams.

כל מקטע מכל הזרמים הוא Uint8Array. בניגוד לממשקי ה-API של Datagram, ההעברות האלה מהימנות. עם זאת, כל מקור נתונים הוא עצמאי, ולכן אין ערובה לסדר הנתונים בין המקורות השונים.

WebTransportSendStream

לקוח האינטרנט יוצר WebTransportSendStream באמצעות השיטה createUnidirectionalStream() של מופע WebTransport, שמחזירה הבטחה ל-WebTransportSendStream.

משתמשים בשיטה close() של WritableStreamDefaultWriter כדי לסגור את החיבור המשויך ל-HTTP/3. הדפדפן מנסה לשלוח את כל הנתונים בהמתנה לפני שהוא סוגר את החיבור המשויך בפועל.

// Send two Uint8Arrays to the server.
const stream = await transport.createUnidirectionalStream();
const writer = stream.writable.getWriter();
const data1 = new Uint8Array([65, 66, 67]);
const data2 = new Uint8Array([68, 69, 70]);
writer.write(data1);
writer.write(data2);
try {
  await writer.close();
  console.log('All data has been sent.');
} catch (error) {
  console.error(`An error occurred: ${error}`);
}

באופן דומה, משתמשים בשיטה abort() של WritableStreamDefaultWriter כדי לשלוח RESET\_STREAM לשרת. כשמשתמשים ב-abort(), הדפדפן עשוי להשליך נתונים בהמתנה שעדיין לא נשלחו.

const ws = await transport.createUnidirectionalStream();
const writer = ws.getWriter();
writer.write(...);
writer.write(...);
await writer.abort();
// Not all the data may have been written.

WebTransportReceiveStream

WebTransportReceiveStream מופעל על ידי השרת. קבלת WebTransportReceiveStream היא תהליך דו-שלבי עבור לקוח אינטרנט. קודם כול, היא קוראת למאפיין incomingUnidirectionalStreams של מכונה WebTransport, שמחזיר ReadableStream. כל מקטע של ReadableStream הוא WebTransportReceiveStream שאפשר להשתמש בו כדי לקרוא את המופעים של Uint8Array שנשלחים מהשרת.

async function readFrom(receiveStream) {
  const reader = receiveStream.readable.getReader();
  while (true) {
    const {done, value} = await reader.read();
    if (done) {
      break;
    }
    // value is a Uint8Array
    console.log(value);
  }
}

const rs = transport.incomingUnidirectionalStreams;
const reader = rs.getReader();
while (true) {
  const {done, value} = await reader.read();
  if (done) {
    break;
  }
  // value is an instance of WebTransportReceiveStream
  await readFrom(value);
}

אפשר לזהות סגירת מקור נתונים באמצעות ההבטחה closed של ReadableStreamDefaultReader. כשהחיבור הבסיסי של HTTP/3 נסגר באמצעות הביט 'FIN', ההתחייבות של closed מתקיימת אחרי שכל הנתונים נקראו. כשהחיבור ל-HTTP/3 נסגר באופן פתאומי (לדוגמה, על ידי RESET\_STREAM), ההתחייבות closed נדחית.

// Assume an active receiveStream
const reader = receiveStream.readable.getReader();
reader.closed.then(() => {
  console.log('The receiveStream closed gracefully.');
}).catch(() => {
  console.error('The receiveStream closed abruptly.');
});

WebTransportBidirectionalStream

השרת או הלקוח יכולים ליצור את WebTransportBidirectionalStream.

לקוחות אינטרנט יכולים ליצור אחד באמצעות השיטה createBidirectionalStream() של מופע WebTransport, שמחזירה הבטחה ל-WebTransportBidirectionalStream.

const stream = await transport.createBidirectionalStream();
// stream is a WebTransportBidirectionalStream
// stream.readable is a ReadableStream
// stream.writable is a WritableStream

אפשר להאזין ל-WebTransportBidirectionalStream שנוצר על ידי השרת באמצעות המאפיין incomingBidirectionalStreams של מכונה WebTransport, שמחזיר ReadableStream. כל מקטע של ReadableStream הוא WebTransportBidirectionalStream.

const rs = transport.incomingBidirectionalStreams;
const reader = rs.getReader();
while (true) {
  const {done, value} = await reader.read();
  if (done) {
    break;
  }
  // value is a WebTransportBidirectionalStream
  // value.readable is a ReadableStream
  // value.writable is a WritableStream
}

WebTransportBidirectionalStream הוא פשוט שילוב של WebTransportSendStream ו-WebTransportReceiveStream. הדוגמאות משני הקטעים הקודמים ממחישות איך משתמשים בכל אחת מהן.

דוגמאות נוספות

טיוטת המפרט של WebTransport כוללת מספר דוגמאות נוספות בתוך הטקסט, יחד עם תיעוד מלא של כל השיטות והמאפיינים.

WebTransport בכלי הפיתוח של Chrome

לצערנו, כלי הפיתוח של Chrome לא תומכים כרגע ב-WebTransport. אתם יכולים לסמן את הבעיה הזו ב-Chrome בכוכב כדי לקבל התראות על עדכונים בממשק של DevTools.

פוליפיל

יש polyfill (או ponyfill, שמשמש כמודול עצמאי שאפשר להשתמש בו) שנקרא webtransport-ponyfill-websocket שמטמיע חלק מהתכונות של WebTransport. חשוב לקרוא בעיון את האילוצים שמפורטים בקובץ README של הפרויקט כדי לקבוע אם הפתרון הזה מתאים לתרחיש לדוגמה שלכם.

שיקולים לגבי פרטיות ואבטחה

כדי לקבל הנחיות מהימנות, אפשר לעיין בקטע התואם בטיוטת המפרט.

משוב

צוות Chrome רוצה לשמוע את המחשבות והחוויות שלכם לגבי ה-API הזה.

משוב על עיצוב ה-API

האם יש משהו ב-API שקשה להשתמש בו או שהוא לא פועל כצפוי? או שיש לכם חסרים שצריך למלא כדי להטמיע את הרעיון?

אפשר לדווח על בעיה במאגר GitHub של Web Transport או להוסיף את דעתכם לבעיה קיימת.

בעיה בהטמעה?

מצאתם באג בהטמעה של Chrome?

שולחים דיווח על באג בכתובת https://new.crbug.com. חשוב לציין כמה שיותר פרטים, וגם הוראות פשוטות לשחזור הבעיה.

מתכננים להשתמש ב-API?

התמיכה הציבורית שלכם עוזרת לנו לקבוע את סדר העדיפויות של התכונות ב-Chrome, ומראה ליצרני דפדפנים אחרים כמה חשובה התמיכה בהם.

  • שולחים ציוץ אל @ChromiumDev עם האשטאג #WebTransport ופרטים על המיקום שבו אתם משתמשים ב-Chromium ועל אופן השימוש.

דיון כללי

אפשר להשתמש בקבוצת Google web-transport-dev לשאלות כלליות או לבעיות שלא מתאימות לאף אחת מהקטגוריות האחרות.

תודות

המאמר הזה מבוסס על מידע מהסבר על WebTransport, מטיוטת המפרט וממסמכים קשורים בנושא עיצוב. תודה לכותבים הרלוונטיים על הבסיס הזה.

התמונה הראשית (Hero) בפוסט הזה היא של Robin Pierre ב-Unsplash.