תאריך פרסום: 8 ביוני 2020
WebTransport הוא API לאינטרנט שמשתמש בפרוטוקול HTTP/3 כהעברה דו-כיוונית. הפרוטוקול מיועד לתקשורת דו-כיוונית בין לקוח אינטרנט לבין שרת HTTP/3. הוא תומך בשליחת נתונים בצורה לא אמינה באמצעות datagram APIs, ובצורה אמינה באמצעות streams APIs.
Datagrams הם אידיאליים לשליחה ולקבלה של נתונים שלא צריך להבטיח את המסירה שלהם. הגודל של כל חבילת נתונים מוגבל על ידי יחידת השידור המקסימלית (MTU) של החיבור הבסיסי, והיא עשויה להיות מועברת בהצלחה או לא, ואם היא מועברת, היא עשויה להגיע בסדר אקראי. המאפיינים האלה הופכים את ממשקי ה-API של חבילות הנתונים לאידיאליים להעברת נתונים עם חביון נמוך, שנעשית על בסיס המאמץ המרבי. אפשר לחשוב על דאטגרמים כהודעות של פרוטוקול דאטגרם משתמש (UDP), אבל מוצפנות ועם בקרת עומס.
לעומת זאת, ממשקי ה-API של הזרמים מספקים העברת נתונים אמינה ומסודרת. הם מתאימים לתרחישים שבהם צריך לשלוח או לקבל זרם אחד או יותר של נתונים מסודרים. השימוש בכמה סטרימים של WebTransport דומה ליצירה של כמה חיבורי TCP, אבל מכיוון ש-HTTP/3 משתמש בפרוטוקול QUIC הקל יותר מתחת לפני השטח, אפשר לפתוח ולסגור אותם בלי תקורה גבוהה מדי.
תרחישים לדוגמה
זו רשימה קצרה של דרכים אפשריות שבהן מפתחים יכולים להשתמש ב-WebTransport.
- שליחת מצב המשחק במרווחי זמן קבועים עם זמן אחזור מינימלי לשרת בהודעות קטנות, לא אמינות ולא מסודרות.
- קבלת סטרימינג של מדיה שנשלח משרת עם השהיה מינימלית, ללא תלות בסטרימינג של נתונים אחרים.
- קבלת התראות שנשלחות משרת בזמן שדף אינטרנט פתוח.
נשמח לשמוע עוד על האופן שבו אתם מתכננים להשתמש ב-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, הוא תומך באופטימיזציות שקשורות ל-backpressure.
עם זאת, אם כבר יש לכם הגדרת לקוח/שרת של WebRTC שפועלת ואתם מרוצים ממנה, יכול להיות שמעבר ל-WebTransport לא יציע לכם הרבה יתרונות.
ניסוי
הדרך הכי טובה להתנסות ב-WebTransport היא להפעיל שרת HTTP/3 תואם. אפשר להשתמש בדף הזה עם לקוח JavaScript בסיסי כדי לנסות תקשורת בין לקוח לשרת.
בנוסף, שרת הד של קהילה זמין בכתובת webtransport.day.
שימוש ב-API
פרוטוקול WebTransport מבוסס על פרימיטיבים מודרניים של פלטפורמת האינטרנט, כמו Streams API. היא מסתמכת במידה רבה על promises, ופועלת היטב עם async ועם await.
ההטמעה הנוכחית של WebTransport ב-Chromium תומכת בשלושה סוגים שונים של תנועה: דאטגרמות וגם סטרימים חד-כיווניים ודו-כיווניים.
התחברות לשרת
כדי להתחבר לשרת 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 APIs
אחרי שיוצרים מופע WebTransport שמחובר לשרת, אפשר להשתמש בו כדי לשלוח ולקבל חלקי נתונים נפרדים, שנקראים דאטגרמים.
הפונקציה writeable getter מחזירה WritableStream, שבאמצעותה לקוח אינטרנט יכול לשלוח נתונים לשרת. הפונקציה readable getter מחזירה 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);
}
Streams APIs
אחרי שמתחברים לשרת, אפשר גם להשתמש ב-WebTransport כדי לשלוח ולקבל נתונים דרך ממשקי ה-API של הזרמים שלו.
כל מקטע של כל הזרמים הוא 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. בדוגמאות משני הקטעים הקודמים מוסבר איך משתמשים בכל אחת מהשיטות.
פוליפיל
יש polyfill (או ponyfill, שכולל פונקציונליות כמודול עצמאי שאפשר להשתמש בו) בשם webtransport-ponyfill-websocket, שמטמיע חלק מהתכונות של WebTransport. חשוב לקרוא בעיון את האילוצים שמופיעים ב-README של הפרויקט כדי לקבוע אם הפתרון הזה מתאים לתרחיש השימוש שלכם.
שיקולי פרטיות ואבטחה
הנחיות מוסמכות מופיעות בקטע הרלוונטי במפרט הטיוטה.
משוב
האם יש משהו ב-API שגורם לבעיות או שלא פועל כמצופה? או שחסרים לך חלקים כדי ליישם את הרעיון?
- אפשר לפתוח בעיה במאגר Web Transport ב-GitHub או להוסיף את דעתכם לבעיה קיימת.
- דיווח על באג בנוגע להטמעה של Chromium. חשוב לספק כמה שיותר פרטים, כולל הוראות לשחזור הבעיה.
התמיכה הציבורית שלכם עוזרת ל-Chrome לתת עדיפות לתכונות, ומראה לספקי דפדפנים אחרים כמה חשוב לתמוך בהן.
- אפשר לצייץ אל @ChromiumDev באמצעות ההאשטאג
#WebTransportולפרט איפה ואיך אתם משתמשים בו.
דיון כללי
אפשר להשתמש בקבוצת Google web-transport-dev לשאלות כלליות או לבעיות שלא מתאימות לאף אחת מהקטגוריות האחרות.
תודות
שילבנו מידע מהסבר על WebTransport ומטיוטת המפרט. תודה למחברים הרלוונטיים על כך שהניחו את הבסיס הזה.