วิธีใช้ WebTransport

เผยแพร่: 8 มิถุนายน 2020

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

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

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

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

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

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

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

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

Browser Support

  • Chrome: 97.
  • Edge: 97.
  • Firefox: 114.
  • Safari: 26.4.

Source

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

ความเกี่ยวข้องกับเทคโนโลยีอื่นๆ

WebTransport ใช้แทน WebSocket ได้ไหม

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

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

เมื่อใช้ WebTransport กับ Datagram API หรืออินสแตนซ์ API ของสตรีมพร้อมกันหลายรายการ คุณไม่ต้องกังวลเกี่ยวกับการบล็อกที่หัวของบรรทัด ซึ่งอาจเป็นปัญหาใน WebSockets นอกจากนี้ การสร้างการเชื่อมต่อใหม่ยังช่วยเพิ่มประสิทธิภาพได้ด้วย เนื่องจากแฮนด์เชค QUIC ที่อยู่เบื้องหลังนั้นเร็วกว่าการเริ่มต้น TCP ผ่าน TLS

WebTransport เป็นส่วนหนึ่งของข้อกำหนดฉบับร่างใหม่ และด้วยเหตุนี้ ระบบนิเวศ WebSocket รอบๆ ไลบรารีไคลเอ็นต์และเซิร์ฟเวอร์จึงมีประสิทธิภาพมากขึ้น หากคุณต้องการสิ่งที่ใช้งานได้ "ทันที" กับการตั้งค่าเซิร์ฟเวอร์ทั่วไปและรองรับไคลเอ็นต์เว็บอย่างกว้างขวาง WebSocket เป็นตัวเลือกที่ดีกว่าในปัจจุบัน

WebTransport เหมือนกับ UDP Socket API ไหม

ไม่ WebTransport ไม่ใช่ UDP Socket API แม้ว่า WebTransport จะใช้ HTTP/3 ซึ่งใช้ UDP "เบื้องหลัง" แต่ WebTransport มีข้อกำหนดเกี่ยวกับการเข้ารหัสและการควบคุมความแออัดที่ทำให้ WebTransport เป็นมากกว่า API ซ็อกเก็ต UDP พื้นฐาน

WebTransport เป็นทางเลือกแทนช่องข้อมูล WebRTC หรือไม่

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

โดยทั่วไป การเรียกใช้เซิร์ฟเวอร์ที่รองรับ HTTP/3 จะต้องมีการตั้งค่าและการกำหนดค่าน้อยกว่าการดูแลเซิร์ฟเวอร์ WebRTC ซึ่งเกี่ยวข้องกับการทำความเข้าใจโปรโตคอลหลายรายการ (ICE, DTLS และ SCTP) เพื่อให้ได้การรับส่งที่ใช้งานได้ WebRTC มีองค์ประกอบที่เคลื่อนไหวได้อีกมากมายซึ่งอาจทำให้การเจรจาระหว่างไคลเอ็นต์กับเซิร์ฟเวอร์ไม่สำเร็จ

WebTransport API ได้รับการออกแบบโดยคำนึงถึง Use Case ของนักพัฒนาเว็บ และควรให้ความรู้สึกเหมือนการเขียนโค้ดแพลตฟอร์มเว็บสมัยใหม่มากกว่าการใช้อินเทอร์เฟซช่องข้อมูลของ WebRTC WebTransport รองรับภายใน Web Worker ซึ่งช่วยให้คุณสื่อสารระหว่างไคลเอ็นต์กับเซิร์ฟเวอร์ได้โดยไม่ขึ้นอยู่กับหน้า HTML ที่กำหนด เนื่องจาก WebTransport แสดงอินเทอร์เฟซที่สอดคล้องกับ Streams จึงรองรับการเพิ่มประสิทธิภาพเกี่ยวกับแรงดันย้อนกลับ

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

การทดลอง

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

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

ใช้ API

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

การใช้งาน WebTransport ใน Chromium ปัจจุบันรองรับการรับส่งข้อมูล 3 ประเภท ได้แก่ Datagram รวมถึงสตรีมแบบทิศทางเดียวและแบบสองทิศทาง

เชื่อมต่อกับเซิร์ฟเวอร์

คุณเชื่อมต่อกับเซิร์ฟเวอร์ HTTP/3 ได้โดยการสร้างWebTransportอินสแตนซ์ รูปแบบของ URL ควรเป็น https คุณต้องระบุหมายเลขพอร์ตอย่างชัดเจน

คุณควรใช้สัญญา ready เพื่อรอให้สร้างการเชื่อมต่อ สัญญาดังกล่าวจะยังไม่เป็นไปตามที่ระบุไว้จนกว่าการตั้งค่าจะเสร็จสมบูรณ์ และจะปฏิเสธหากการเชื่อมต่อล้มเหลวในขั้นตอน QUIC/TLS

closed Promise จะดำเนินการให้เสร็จสมบูรณ์เมื่อการเชื่อมต่อปิดตามปกติ และจะปฏิเสธหากการปิดนั้นไม่คาดคิด

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

สตรีมทั้ง 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);
}

Streams APIs

เมื่อเชื่อมต่อกับเซิร์ฟเวอร์แล้ว คุณยังใช้ WebTransport เพื่อส่งและรับข้อมูลผ่าน Streams API ได้ด้วย

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

WebTransportSendStream

ไคลเอ็นต์ของเว็บจะสร้าง WebTransportSendStream โดยใช้วิธี createUnidirectionalStream() ของอินสแตนซ์ WebTransport ซึ่งจะแสดงผล Promise สำหรับ 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 เป็นกระบวนการ 2 ขั้นตอนสำหรับไคลเอ็นต์บนเว็บ ก่อนอื่น ไคลเอ็นต์จะเรียกแอตทริบิวต์ 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);
}

คุณตรวจหาการปิดสตรีมได้โดยใช้ Promise 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 ซึ่งจะแสดงผล 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 ตัวอย่างจาก 2 ส่วนก่อนหน้าจะอธิบายวิธีใช้แต่ละรายการ

Polyfill

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

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

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

ความคิดเห็น

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

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

  • ทวีตถึง @ChromiumDev โดยใช้แฮชแท็ก #WebTransport และรายละเอียดเกี่ยวกับสถานที่และวิธีที่คุณใช้

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

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

คำขอบคุณ

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