การใช้ WebTransport

WebTransport คือ API ที่นำเสนอการส่งข้อความแบบไคลเอ็นต์-เซิร์ฟเวอร์แบบสองทิศทางโดยมีเวลาในการตอบสนองต่ำ ดูข้อมูลเพิ่มเติมเกี่ยวกับกรณีการใช้งานและวิธีแสดงความคิดเห็นเกี่ยวกับอนาคตของการนำไปใช้งาน

ข้อมูลเบื้องต้น

WebTransport คืออะไร

WebTransport คือ Web API ที่ใช้โปรโตคอล HTTP/3 เป็นการรับส่งข้อมูลแบบ 2 ทิศทาง โดยมีไว้สำหรับการสื่อสารแบบ 2 ทางระหว่างเว็บไคลเอ็นต์และเซิร์ฟเวอร์ HTTP/3 โปรโตคอลนี้รองรับการส่งข้อมูลผ่าน API ของ Datagram และไม่มีความน่าเชื่อถือผ่าน Streams API

Datagrams เหมาะสำหรับการส่งและรับข้อมูลที่ไม่ต้องการการรับประกันการแสดงโฆษณาอย่างเข้มงวด แพ็กเก็ตข้อมูลแต่ละแพ็กจะมีขนาดจำกัดตามหน่วยการส่งสูงสุด (MTU) ของการเชื่อมต่อพื้นฐาน และอาจส่งไม่สำเร็จหรือส่งไม่สำเร็จ และหากมีการโอน แพ็กเก็ตอาจจะมาถึงตามลำดับที่กำหนดเอง ลักษณะเฉพาะเหล่านี้ทำให้ API ของ Datagram เหมาะสำหรับการส่งข้อมูลแบบเวลาในการตอบสนองต่ำและใช้ความพยายามอย่างดีที่สุด คุณอาจมองว่า Datagram เป็นข้อความโปรโตคอล Datagram Protocol (UDP) ของผู้ใช้ แต่มีการเข้ารหัสและควบคุมความคับคั่งได้

ในทางกลับกัน API ของสตรีมจะให้การโอนข้อมูลตามลำดับที่เชื่อถือได้ ซึ่งเหมาะสมกับสถานการณ์ที่คุณต้องการส่งหรือรับสตรีมข้อมูลตามลำดับอย่างน้อย 1 รายการ การใช้สตรีม WebTransport หลายรายการคล้ายกับการสร้างการเชื่อมต่อ TCP หลายรายการ แต่เนื่องจาก HTTP/3 ใช้โปรโตคอล QUIC ขนาดเล็กอยู่ในระบบ จึงสามารถเปิดและปิดได้โดยไม่ต้องใช้ต้นทุนมากนัก

กรณีการใช้งาน

ต่อไปนี้เป็นรายการเล็กๆ น้อยๆ ของวิธีที่นักพัฒนาซอฟต์แวร์อาจใช้ WebTransport

  • การส่งสถานะเกมตามช่วงเวลาปกติโดยมีเวลาในการตอบสนองไปยังเซิร์ฟเวอร์น้อยที่สุดผ่านข้อความขนาดเล็กที่ไม่น่าเชื่อถือ และไม่เป็นระเบียบ
  • การรับสตรีมสื่อที่พุชจากเซิร์ฟเวอร์โดยมีเวลาในการตอบสนองน้อยที่สุดโดยไม่ขึ้นอยู่กับสตรีมข้อมูลอื่นๆ
  • การรับการแจ้งเตือนที่พุชจากเซิร์ฟเวอร์ขณะที่หน้าเว็บเปิดอยู่

เราต้องการรับฟังข้อมูลเพิ่มเติมเกี่ยวกับวิธีที่คุณวางแผนจะใช้ WebTransport

การสนับสนุนเบราว์เซอร์

การรองรับเบราว์เซอร์

  • Chrome: 97.
  • ขอบ: 97
  • Firefox: 114
  • Safari: ไม่รองรับ

แหล่งที่มา

แนวทางปฏิบัติแนะนำคือการเขียนโค้ดเพื่อป้องกันตัวเองผ่านการตรวจหาฟีเจอร์เช่นเดียวกับฟีเจอร์ทั้งหมดที่ไม่รองรับเบราว์เซอร์แบบสากล

สถานะปัจจุบัน

ขั้นตอน สถานะ
1. สร้างคำอธิบาย เสร็จสมบูรณ์
2. สร้างข้อกำหนดคร่าวๆ เบื้องต้น เสร็จสมบูรณ์
3. รวบรวมความคิดเห็นและทำซ้ำการออกแบบ เสร็จสมบูรณ์
4. ช่วงทดลองใช้จากต้นทาง เสร็จสมบูรณ์
5. เปิดตัว Chromium 97

ความสัมพันธ์ของ WebTransport กับเทคโนโลยีอื่นๆ

WebTransport มาใช้แทน WebSockets ใช่ไหม

อาจจะได้ ในบางกรณีที่ WebSockets หรือ WebTransport อาจเป็นโปรโตคอลการสื่อสารที่ถูกต้อง

การสื่อสารของ WebSockets นั้นมาจากรูปแบบข้อความเดียวที่เชื่อถือได้และเรียงตามลำดับ ซึ่งเหมาะสำหรับการสื่อสารบางประเภท หากคุณต้องการลักษณะเฉพาะดังกล่าว API สตรีมของ WebTransport ก็จัดทำได้เช่นกัน เมื่อเปรียบเทียบกันแล้ว API ของ Datagram ของ WebTransport มอบการนำส่งที่มีเวลาในการตอบสนองต่ำโดยไม่มีการรับประกันเรื่องความน่าเชื่อถือหรือการสั่งซื้อ ดังนั้น API ดังกล่าวจึงไม่ใช่ตัวแทนที่ WebSockets โดยตรง

การใช้ WebTransport ผ่าน API ของ Datagram หรือผ่านอินสแตนซ์ 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 Worker ซึ่งช่วยให้คุณสื่อสารระหว่างไคลเอ็นต์-เซิร์ฟเวอร์โดยไม่ขึ้นอยู่กับหน้า HTML ที่กำหนด เนื่องจาก WebTransport แสดงอินเทอร์เฟซที่สอดคล้องกับสตรีม จึงรองรับการเพิ่มประสิทธิภาพเกี่ยวกับแรงดันย้อนกลับ

อย่างไรก็ตาม หากคุณมีการตั้งค่าไคลเอ็นต์/เซิร์ฟเวอร์ WebRTC ที่ใช้งานได้ที่คุณพอใจ การเปลี่ยนไปใช้ WebTransport อาจไม่ใช่ข้อดีมากนัก

ลองเลย

วิธีที่ดีที่สุดในการทดสอบกับ WebTransport คือการเริ่มต้นเซิร์ฟเวอร์ HTTP/3 ที่ใช้งานร่วมกันได้ จากนั้นคุณสามารถใช้หน้านี้กับไคลเอ็นต์ JavaScript พื้นฐานเพื่อลองใช้การสื่อสารระหว่างไคลเอ็นต์/เซิร์ฟเวอร์

นอกจากนี้ คุณยังดูเซิร์ฟเวอร์ Echo ที่ได้รับการดูแลโดยชุมชนได้ที่ webtransport.day

การใช้ API

WebTransport ออกแบบมาบนพื้นฐานของแพลตฟอร์มเว็บสมัยใหม่ เช่น Streams API ซึ่งอาศัย promise เป็นหลัก และทำงานได้ดีกับ async และ await

การใช้งาน WebTransport ในปัจจุบันใน Chromium รองรับการเข้าชมที่แตกต่างกัน 3 ประเภท ได้แก่ 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

เมธอด writeable แสดงผล WritableStream ซึ่งเว็บไคลเอ็นต์ใช้เพื่อส่งข้อมูลไปยังเซิร์ฟเวอร์ได้ เมธอด readable แสดงผล ReadableStream ซึ่งจะช่วยให้คุณฟังข้อมูลจากเซิร์ฟเวอร์ได้ โดยพื้นฐานแล้ว สตรีมทั้งสองไม่น่าเชื่อถือ จึงเป็นไปได้ว่าเซิร์ฟเวอร์จะไม่รับข้อมูลที่คุณเขียนและในทางกลับกัน

สตรีมทั้ง 2 ประเภทใช้อินสแตนซ์ 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 สตรีมเหล่านี้มีความน่าเชื่อถือ ซึ่งต่างจาก Datagram API แต่สตรีมแต่ละรายการเป็นอิสระจากกัน จึงไม่รับประกันลำดับของข้อมูลในสตรีม

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 ตัวอย่างจาก 2 ส่วนก่อนหน้านี้อธิบายถึงวิธีใช้แต่ละรูปแบบ

ตัวอย่างเพิ่มเติม

ข้อกำหนดฉบับร่างของ WebTransport ประกอบด้วยตัวอย่างในบรรทัดเพิ่มเติมจำนวนหนึ่ง พร้อมเอกสารฉบับเต็มสำหรับเมธอดและพร็อพเพอร์ตี้ทั้งหมด

WebTransport ในเครื่องมือสำหรับนักพัฒนาเว็บของ Chrome

ขออภัย ปัจจุบันเครื่องมือสำหรับนักพัฒนาเว็บของ Chrome ไม่รองรับ WebTransport คุณสามารถ "ติดดาว" ปัญหาเกี่ยวกับ Chrome นี้เพื่อรับการแจ้งเตือนเกี่ยวกับการอัปเดตในอินเทอร์เฟซเครื่องมือสำหรับนักพัฒนาเว็บ

ใยโพลีเอสเตอร์

Polyfill (หรือแทนการใช้ ponyfill ซึ่งมีฟังก์ชันการทำงานเป็นโมดูลเดี่ยวๆ ที่คุณสามารถใช้ได้) ที่เรียกว่า webtransport-ponyfill-websocket ที่มีการใช้ฟีเจอร์บางอย่างของ WebTransport อ่านข้อจำกัดใน READMEของโปรเจ็กต์เพื่อดูว่าโซลูชันนี้เหมาะกับกรณีการใช้งานของคุณไหม

ข้อควรพิจารณาเกี่ยวกับความเป็นส่วนตัวและความปลอดภัย

ดูส่วนที่เกี่ยวข้องของข้อกำหนดฉบับร่างสำหรับคำแนะนำที่เชื่อถือได้

ความคิดเห็น

ทีม Chrome อยากทราบความคิดเห็นและประสบการณ์ของคุณเมื่อใช้ API นี้

ความคิดเห็นเกี่ยวกับการออกแบบ API

มีบางอย่างเกี่ยวกับ API ที่แปลกหรือไม่ทำงานตามที่คาดไว้ไหม หรือยังมีส่วนที่ขาดหายไปที่คุณต้องนำไอเดียของคุณไปปฏิบัติหรือไม่

แจ้งปัญหาในที่เก็บ GitHub สำหรับการส่งเว็บ หรือเพิ่มความเห็นเกี่ยวกับปัญหาที่มีอยู่

หากมีปัญหาในการติดตั้งใช้งาน

คุณพบข้อบกพร่องในการติดตั้งใช้งาน Chrome ไหม

รายงานข้อบกพร่องที่ https://new.crbug.com ระบุรายละเอียดให้มากที่สุดเท่าที่จะทำได้ พร้อมกับวิธีการง่ายๆ ในการทำซ้ำ

หากกำลังวางแผนที่จะใช้ API

การสนับสนุนสาธารณะของคุณช่วยให้ Chrome จัดลำดับความสำคัญของฟีเจอร์ต่างๆ และแสดงให้ผู้ให้บริการเบราว์เซอร์รายอื่นเห็นว่าการสนับสนุนเหล่านั้นสำคัญมากแค่ไหน

  • ส่งทวีตไปยัง @ChromiumDev โดยใช้แฮชแท็ก #WebTransport และรายละเอียดเกี่ยวกับตำแหน่งและวิธี การใช้งาน

การสนทนาทั่วไป

คุณสามารถใช้ web-transport-dev Google Group เพื่อถามคำถามหรือแก้ปัญหาทั่วไปที่ไม่เข้ากับหมวดหมู่อื่นๆ ได้

กิตติกรรมประกาศ

บทความนี้มีข้อมูลจากคำอธิบาย WebTransport, ข้อกำหนดฉบับร่าง และเอกสารการออกแบบที่เกี่ยวข้อง ขอขอบคุณผู้เขียนแต่ละท่านที่ให้เงินสนับสนุน

รูปภาพหลักในโพสต์นี้เขียนโดย Robin Pierre ใน Unsplash