تاريخ النشر: 8 يونيو 2020
WebTransport هي واجهة برمجة تطبيقات على الويب تستخدم بروتوكول HTTP/3 كنقل ثنائي الاتجاه. وهو مصمّم لإجراء اتصالات ثنائية الاتجاه بين عميل ويب وخادم HTTP/3. تتيح إرسال البيانات بشكل غير موثوق به باستخدام واجهات برمجة تطبيقات حزم البيانات، وبشكل موثوق به باستخدام واجهات برمجة تطبيقات عمليات البث.
تُعد مخططات البيانات مثالية لإرسال البيانات واستلامها، ولا تحتاج إلى ضمانات قوية بشأن التسليم. تكون حِزم البيانات الفردية محدودة الحجم بموجب وحدة الإرسال القصوى (MTU) للاتصال الأساسي، وقد يتم إرسالها بنجاح أو لا، وإذا تم نقلها، قد تصل بترتيب عشوائي. تجعل هذه الخصائص واجهات برمجة التطبيقات الخاصة بحزم البيانات مثالية لنقل البيانات بأقل وقت استجابة وبأفضل جهد ممكن. يمكنك اعتبار مخططات البيانات بمثابة رسائل بروتوكول مخطط بيانات المستخدم (UDP)، ولكنها مشفّرة ويتم التحكّم في الازدحام فيها.
في المقابل، توفّر واجهات برمجة التطبيقات الخاصة بالتدفقات نقل بيانات موثوقًا ومنظَّمًا. وهي مناسبة للسيناريوهات التي تحتاج فيها إلى إرسال أو تلقّي مصدر واحد أو أكثر من البيانات المنظَّمة. إنّ استخدام عدة قنوات WebTransport يشبه إنشاء عدة اتصالات TCP، ولكن بما أنّ HTTP/3 يستخدم بروتوكول QUIC الأخف وزنًا في الخلفية، يمكن فتحها وإغلاقها بدون الكثير من النفقات العامة.
حالات الاستخدام
في ما يلي قائمة صغيرة بالطرق المحتملة التي يمكن للمطوّرين استخدام WebTransport بها.
- إرسال حالة اللعبة على فترات منتظمة مع الحد الأدنى من وقت الاستجابة إلى خادم في رسائل صغيرة وغير موثوقة وغير مرتبة
- تلقّي بث الوسائط الذي يتم إرساله من خادم بأقل وقت استجابة ممكن، وبشكل مستقل عن بث البيانات الأخرى
- تلقّي إشعارات يتم إرسالها من خادم أثناء فتح صفحة ويب
يهمّنا معرفة المزيد عن طريقة استخدامك لبروتوكول WebTransport.
دعم المتصفح
كما هو الحال مع جميع الميزات التي لا تتوافق مع جميع المتصفّحات، ننصحك بإضافة ميزة رصد.
الصلة بالتكنولوجيات الأخرى
هل WebTransport بديل لبروتوكول WebSockets؟
ربما. هناك حالات استخدام قد يكون فيها WebSockets أو WebTransport بروتوكولَي اتصال صالحَين للاستخدام.
تستند اتصالات WebSockets إلى بث واحد موثوق ومنظَّم للرسائل، وهو أمر مناسب لبعض أنواع احتياجات الاتصال. إذا كنت بحاجة إلى هذه الخصائص، يمكن أن توفّرها لك واجهات برمجة التطبيقات الخاصة بتدفقات WebTransport أيضًا. في المقابل، توفّر واجهات برمجة التطبيقات الخاصة بمخططات بيانات WebTransport إمكانية نقل البيانات بزمن انتقال منخفض، بدون ضمانات بشأن الموثوقية أو الترتيب، لذا فهي ليست بديلاً مباشرًا عن WebSockets.
عند استخدام WebTransport، سواء مع واجهات برمجة التطبيقات الخاصة بحزم البيانات أو مثيلات متعددة ومتزامنة من واجهة برمجة التطبيقات Streams، لن تقلق بشأن حظر بداية السطر، وهو ما قد يمثّل مشكلة مع WebSockets. بالإضافة إلى ذلك، هناك مزايا متعلّقة بالأداء عند إنشاء اتصالات جديدة، لأنّ تأكيد الاتصال باستخدام بروتوكول QUIC الأساسي أسرع من بدء بروتوكول TCP عبر TLS.
تشكّل WebTransport جزءًا من مسودة مواصفات جديدة، وبالتالي فإنّ نظام WebSocket المتكامل حول مكتبات العميل والخادم أكثر فعالية. إذا كنت بحاجة إلى شيء يعمل "بدون أي إعدادات" مع إعدادات الخادم الشائعة، ويتوافق مع مجموعة كبيرة من برامج الويب، فإنّ WebSockets هو الخيار الأفضل اليوم.
هل WebTransport هي نفسها واجهة برمجة تطبيقات UDP Socket؟
لا، WebTransport ليس UDP Socket API. على الرغم من أنّ WebTransport تستخدم HTTP/3، التي تستخدم بدورها بروتوكول UDP "بشكل غير مرئي"، إلا أنّ WebTransport لديها متطلبات بشأن التشفير والتحكّم في الازدحام تجعلها أكثر من مجرد واجهة برمجة تطبيقات أساسية لمقبس UDP.
هل 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 لتجربة عمليات التواصل بين العميل والخادم.
بالإضافة إلى ذلك، يتوفّر خادم echo يديره المنتدى على webtransport.day.
استخدام واجهة برمجة التطبيقات
تم تصميم WebTransport استنادًا إلى أساسيات حديثة لمنصة الويب، مثل Streams API. تعتمد هذه الطريقة بشكل كبير على الوعود، وتعمل بشكل جيد مع 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 قيمة 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);
}
واجهات برمجة التطبيقات الخاصة بالبث
بعد الاتصال بالخادم، يمكنك أيضًا استخدام WebTransport لإرسال البيانات وتلقّيها من خلال واجهات برمجة التطبيقات الخاصة بـ Streams.
كل جزء من جميع عمليات البث هو Uint8Array. وعلى عكس واجهات برمجة التطبيقات 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
يتوفّر برنامج polyfill (أو بالأحرى ponyfill الذي يوفّر وظائف كوحدة مستقلة يمكنك استخدامها) يُسمى
webtransport-ponyfill-websocket
وينفّذ بعض ميزات WebTransport. اقرأ القيود الواردة في README للمشروع بعناية لتحديد ما إذا كان هذا الحلّ مناسبًا لحالة الاستخدام الخاصة بك.
اعتبارات الخصوصية والأمان
راجِع القسم المعنيّ من مسودة المواصفات للحصول على إرشادات موثوقة.
الملاحظات
هل هناك أي شيء غير مريح أو لا يعمل على النحو المتوقع في واجهة برمجة التطبيقات؟ أو هل هناك أجزاء ناقصة تحتاج إلى تنفيذها لتحقيق فكرتك؟
- يمكنك الإبلاغ عن مشكلة في مستودع Web Transport على GitHub، أو إضافة أفكارك إلى مشكلة حالية.
- يمكنك الإبلاغ عن خطأ بشأن تنفيذ Chromium. يُرجى تضمين أكبر قدر ممكن من التفاصيل، بالإضافة إلى تعليمات حول كيفية إعادة إنتاج المشكلة.
يساعد دعمك العلني Chrome في تحديد أولويات الميزات، ويوضّح لمورّدي المتصفّحات الآخرين مدى أهمية توفيرها.
- يمكنك نشر تغريدة على @ChromiumDev باستخدام الهاشتاغ
#WebTransportوتضمين تفاصيل حول مكان استخدامك له وكيفية استخدامه.
مناقشة عامة
يمكنك استخدام مجموعة Google web-transport-dev لطرح أسئلة عامة أو مشاكل لا تتناسب مع أي من الفئات الأخرى.
الإقرارات
لقد أدرجنا معلومات من شرح WebTransport ومواصفات المسودة. نشكر المؤلّفين المعنيين على توفير هذه الأساسيات.