منتشر شده: ۸ ژوئن ۲۰۲۰
WebTransport یک API وب است که از پروتکل HTTP/3 به عنوان یک انتقال دو طرفه استفاده میکند. این API برای ارتباطات دو طرفه بین یک کلاینت وب و یک سرور HTTP/3 در نظر گرفته شده است. این API از ارسال دادهها هم به صورت غیر قابل اعتماد با APIهای دیتاگرام و هم به صورت قابل اعتماد با APIهای استریم خود پشتیبانی میکند.
دیتاگرامها برای ارسال و دریافت دادههایی که نیازی به تضمین تحویل قوی ندارند، ایدهآل هستند. اندازه بستههای داده به صورت جداگانه توسط حداکثر واحد انتقال (MTU) اتصال اصلی محدود میشود و ممکن است با موفقیت ارسال شوند یا نشوند و اگر ارسال شوند، ممکن است به ترتیب دلخواه برسند. این ویژگیها، APIهای دیتاگرام را برای انتقال داده با تأخیر کم و بهترین تلاش ایدهآل میکند. میتوانید دیتاگرامها را به عنوان پیامهای پروتکل دیتاگرام کاربر (UDP) در نظر بگیرید، اما رمزگذاری شده و از نظر تراکم کنترل شده.
در مقابل، APIهای جریانها، انتقال دادههای قابل اعتماد و منظمی را ارائه میدهند. آنها برای سناریوهایی که نیاز به ارسال یا دریافت یک یا چند جریان از دادههای منظم دارید، بسیار مناسب هستند. استفاده از چندین جریان WebTransport مشابه ایجاد چندین اتصال TCP است، اما از آنجایی که HTTP/3 از پروتکل سبکتر QUIC در پشت صحنه استفاده میکند، میتوان آنها را بدون سربار زیاد باز و بسته کرد.
موارد استفاده
این فهرست کوچکی از روشهای ممکن برای استفاده توسعهدهندگان از WebTransport است.
- ارسال وضعیت بازی در یک بازه زمانی منظم با حداقل تأخیر به سرور در قالب پیامهای کوچک، غیرقابل اعتماد و خارج از ترتیب.
- دریافت جریانهای رسانهای ارسالشده از سرور با حداقل تأخیر، مستقل از سایر جریانهای داده.
- دریافت اعلانهای ارسالی از سرور در حین باز بودن یک صفحه وب.
ما علاقهمندیم اطلاعات بیشتری در مورد نحوهی استفادهی شما از WebTransport بشنویم .
پشتیبانی مرورگر
همانند تمام ویژگیهایی که فاقد پشتیبانی جهانی مرورگر هستند، توصیه میکنیم تشخیص ویژگی را اضافه کنید.
ارتباط با سایر فناوریها
آیا WebTransport جایگزینی برای WebSockets است؟
شاید. مواردی وجود دارد که در آنها WebSockets یا WebTransport ممکن است پروتکلهای ارتباطی معتبری برای استفاده باشند.
ارتباطات WebSockets حول یک جریان واحد، قابل اعتماد و مرتب از پیامها مدلسازی میشوند که برای برخی از انواع نیازهای ارتباطی مناسب است. اگر به این ویژگیها نیاز دارید، APIهای جریان WebTransport نیز میتوانند آنها را ارائه دهند. در مقایسه، APIهای دیتاگرام WebTransport تحویل با تأخیر کم را بدون تضمین قابلیت اطمینان یا مرتبسازی ارائه میدهند، بنابراین جایگزین مستقیمی برای WebSockets نیستند.
وقتی از WebTransport، با APIهای دیتاگرام یا چندین نمونه API استریم همزمان استفاده میکنید، لازم نیست نگران مسدود شدن سر خط باشید، که میتواند مشکلی در WebSockets باشد. علاوه بر این، هنگام ایجاد اتصالات جدید مزایای عملکردی وجود دارد، زیرا دستدهی QUIC اساسی سریعتر از راهاندازی TCP روی TLS است.
WebTransport بخشی از پیشنویس مشخصات جدید است و به همین دلیل اکوسیستم WebSocket پیرامون کتابخانههای کلاینت و سرور بسیار قویتر شده است. اگر به چیزی نیاز دارید که «بهصورت آماده» با تنظیمات رایج سرور و با پشتیبانی گسترده از کلاینت وب کار کند، WebSockets امروزه انتخاب بهتری است.
آیا WebTransport همان UDP Socket API است؟
خیر. WebTransport یک API سوکت UDP نیست. در حالی که WebTransport از HTTP/3 استفاده میکند که به نوبه خود از UDP در «زیر کاپوت» استفاده میکند، WebTransport الزاماتی در مورد رمزگذاری و کنترل ازدحام دارد که آن را به چیزی بیش از یک API سوکت UDP ساده تبدیل میکند.
آیا WebTransport جایگزینی برای کانالهای داده WebRTC است؟
بله، برای اتصالات کلاینت-سرور. WebTransport بسیاری از ویژگیهای مشابه کانالهای داده WebRTC را به اشتراک میگذارد، اگرچه پروتکلهای اساسی آنها متفاوت است.
به طور کلی، اجرای یک سرور سازگار با HTTP/3 به تنظیمات و پیکربندی کمتری نسبت به نگهداری یک سرور WebRTC نیاز دارد، که شامل درک چندین پروتکل ( ICE ، DTLS و SCTP ) برای دستیابی به یک انتقال کارآمد است. WebRTC شامل قطعات متحرک بسیار بیشتری است که میتواند منجر به شکست مذاکرات کلاینت/سرور شود.
API وبترنسپورت با در نظر گرفتن موارد استفاده توسعهدهندگان وب طراحی شده است و باید بیشتر شبیه نوشتن کد پلتفرم وب مدرن باشد تا استفاده از رابطهای کانال داده WebRTC. برخلاف WebRTC ، وبترنسپورت درون Web Workers پشتیبانی میشود که به شما امکان میدهد ارتباطات کلاینت-سرور را مستقل از یک صفحه HTML مشخص انجام دهید. از آنجا که وبترنسپورت یک رابط سازگار با Streams را ارائه میدهد، از بهینهسازیهای مربوط به backpressure پشتیبانی میکند.
با این حال، اگر از قبل یک کلاینت/سرور WebRTC دارید که از آن راضی هستید، تغییر به WebTransport ممکن است مزایای زیادی نداشته باشد.
آزمایش
بهترین راه برای آزمایش WebTransport، راهاندازی یک سرور HTTP/3 سازگار است. از این صفحه با یک کلاینت جاوا اسکریپت ساده برای آزمایش ارتباطات کلاینت و سرور استفاده کنید.
علاوه بر این، یک سرور echo که توسط جامعه پشتیبانی میشود، در webtransport.day در دسترس است.
از API استفاده کنید
WebTransport بر اساس اصول اولیه پلتفرم وب مدرن، مانند Streams API، طراحی شده است. این فریمورک به شدت به promiseها متکی است و با async و await به خوبی کار میکند.
پیادهسازی فعلی WebTransport در Chromium از سه نوع ترافیک مجزا پشتیبانی میکند: دیتاگرامها، و همچنین جریانهای یکطرفه و دوطرفه.
اتصال به یک سرور
شما میتوانید با ایجاد یک نمونه WebTransport به یک سرور HTTP/3 متصل شوید. طرح 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;
APIهای دیتاگرام
زمانی که یک نمونه WebTransport دارید که به یک سرور متصل است، میتوانید از آن برای ارسال و دریافت بیتهای گسسته داده، که به عنوان دیتاگرام شناخته میشوند، استفاده کنید.
تابع دریافت 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های استریم
پس از اتصال به سرور، میتوانید از WebTransport برای ارسال و دریافت دادهها از طریق Streams API های آن نیز استفاده کنید.
هر بخش از تمام جریانها یک Uint8Array است. برخلاف APIهای Datagram، این جریانها قابل اعتماد هستند. اما هر جریان مستقل است، بنابراین ترتیب دادهها در بین جریانها تضمین نمیشود.
WebTransportSendStream
یک WebTransportSendStream توسط کلاینت وب با استفاده از متد createUnidirectionalStream() از یک نمونه WebTransport ایجاد میشود که یک promise برای WebTransportSendStream برمیگرداند.
Use the close() method of the WritableStreamDefaultWriter to close the associated HTTP/3 stream. The browser tries to send all pending data before actually closing the associated stream.
// 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 میتواند توسط سرور یا کلاینت ایجاد شود.
کلاینتهای وب میتوانند با استفاده از متد createBidirectionalStream() از یک نمونه WebTransport ، یکی از آنها را ایجاد کنند، که یک promise برای 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 است. مثالهای دو بخش قبلی نحوه استفاده از هر یک از آنها را توضیح میدهند.
پلیفیل
A polyfill (or rather ponyfill that provides functionality as a standalone module you can use) called webtransport-ponyfill-websocket that implements some of the features of WebTransport is available. Carefully read the constraints in the project's README to determine if this solution can work for your use case.
ملاحظات حریم خصوصی و امنیتی
برای راهنمایی معتبر، به بخش مربوطه از پیشنویس مشخصات مراجعه کنید.
بازخورد
آیا چیزی در مورد API وجود دارد که ناخوشایند است یا آنطور که انتظار میرود کار نمیکند؟ یا قطعات گمشدهای وجود دارد که برای پیادهسازی ایده خود به آنها نیاز دارید؟
- یک مشکل را در مخزن گیتهاب حمل و نقل وب ثبت کنید، یا نظرات خود را به یک مشکل موجود اضافه کنید.
- یک اشکال در مورد پیادهسازی Chromium ثبت کنید. تا جایی که میتوانید جزئیات را به همراه دستورالعملهای تکثیر، ذکر کنید.
پشتیبانی عمومی شما به Chrome کمک میکند تا ویژگیها را در اولویت قرار دهد و به سایر فروشندگان مرورگر نشان میدهد که پشتیبانی از آنها چقدر حیاتی است.
- با استفاده از هشتگ
#WebTransportبه آدرس @ChromiumDev توییت کنید و جزئیات مربوط به مکان و نحوه استفاده از آن را شرح دهید.
بحث عمومی
شما میتوانید از گروه گوگل web-transport-dev برای سوالات یا مشکلاتی که در هیچ یک از دستههای دیگر قرار نمیگیرند، استفاده کنید.
تقدیرنامهها
ما اطلاعات مربوط به WebTransport Explainer و پیشنویس مشخصات را در آن گنجاندهایم. از نویسندگان مربوطه برای ارائه این مبنا متشکریم.