Sử dụng WebTransport

WebTransport là một API cung cấp thông báo máy chủ-máy khách có độ trễ thấp, hai chiều. Tìm hiểu thêm về trường hợp sử dụng và cách gửi ý kiến phản hồi về tương lai của việc triển khai.

Thông tin khái quát

WebTransport là gì?

WebTransport là một API web sử dụng giao thức HTTP/3 làm phương thức truyền tải hai chiều. API này dùng cho hoạt động giao tiếp hai chiều giữa ứng dụng web và máy chủ HTTP/3. Nền tảng này hỗ trợ gửi dữ liệu một cách không đáng tin cậy thông qua API gói dữ liệu và gửi dữ liệu một cách đáng tin cậy thông qua API luồng.

Datagram rất lý tưởng để gửi và nhận dữ liệu không cần sự đảm bảo phân phối rõ ràng. Các gói dữ liệu riêng lẻ được giới hạn kích thước bằng đơn vị truyền tối đa (MTU) của kết nối cơ bản và có thể được truyền thành công hoặc không. Nếu được truyền, các gói dữ liệu này có thể đến theo thứ tự tùy ý. Những đặc điểm này giúp API datagram trở nên lý tưởng để truyền dữ liệu với độ trễ thấp và nỗ lực nhất. Bạn có thể coi datagram là thông điệp giao thức gói dữ liệu người dùng (UDP), nhưng đã được mã hoá và kiểm soát tình trạng nghẽn.

Ngược lại, các API luồng cung cấp tính năng chuyển dữ liệu đáng tin cậy và theo thứ tự. Các chế độ cài đặt này phù hợp với tình huống bạn cần gửi hoặc nhận một hoặc nhiều luồng dữ liệu được sắp xếp theo thứ tự. Việc sử dụng nhiều luồng WebTransport cũng tương tự như việc thiết lập nhiều kết nối TCP. Tuy nhiên, vì HTTP/3 sử dụng giao thức QUIC nhẹ hơn, nên có thể mở và đóng mà không tốn nhiều chi phí.

Trường hợp sử dụng

Đây là danh sách một số cách mà nhà phát triển có thể sử dụng WebTransport.

  • Gửi trạng thái trò chơi định kỳ với độ trễ tối thiểu tới máy chủ qua các tin nhắn nhỏ, không đáng tin cậy và không theo thứ tự.
  • Nhận luồng nội dung nghe nhìn được đẩy từ máy chủ với độ trễ tối thiểu, độc lập với các luồng dữ liệu khác.
  • Nhận thông báo được đẩy từ máy chủ khi trang web đang mở.

Chúng tôi muốn chia sẻ thêm về cách bạn dự định sử dụng WebTransport.

Hỗ trợ trình duyệt

Hỗ trợ trình duyệt

  • 97
  • 97
  • 114
  • x

Nguồn

Tương tự như với mọi tính năng không hỗ trợ trình duyệt chung, phương pháp hay nhất là lập trình để phòng vệ thông qua tính năng phát hiện tính năng.

Trạng thái hiện tại

Bước Trạng thái
1. Tạo thông báo giải thích Hoàn tất
2. Tạo bản nháp ban đầu của quy cách Hoàn tất
3. Thu thập ý kiến phản hồi và lặp lại thiết kế Hoàn chỉnh
4. Bản dùng thử theo nguyên gốc Hoàn chỉnh
5. Chạy Chromium 97

Mối quan hệ của WebTransport với các công nghệ khác

WebTransport có phải là một giải pháp thay thế cho WebSockets không?

Có thể. Có những trường hợp sử dụng mà WebSockets hoặc WebTransport có thể là các giao thức giao tiếp hợp lệ để sử dụng.

Giao tiếp WebSocket được mô hình hoá xoay quanh một luồng thông báo duy nhất, đáng tin cậy và có thứ tự, phù hợp cho một số loại nhu cầu giao tiếp. Nếu bạn cần những đặc điểm đó, thì API luồng của WebTransport cũng có thể cung cấp các đặc điểm đó. So với đó, API datagram của WebTransport cung cấp khả năng phân phối có độ trễ thấp mà không đảm bảo về độ tin cậy hoặc thứ tự, vì vậy, các API này không thay thế trực tiếp cho WebSockets.

Bằng cách sử dụng WebTransport, qua API datagram hoặc qua nhiều thực thể API luồng đồng thời, bạn sẽ không phải lo lắng về việc chặn đầu dòng, đây có thể là vấn đề với WebSockets. Ngoài ra, việc thiết lập kết nối mới cũng mang lại một số lợi ích về hiệu suất, vì cơ chế bắt tay QUIC (cơ bản) nhanh hơn so với việc khởi động TCP qua TLS.

WebTransport là một phần của quy cách nháp mới, do đó, hệ sinh thái WebSocket xoay quanh thư viện ứng dụng khách và máy chủ hiện mạnh mẽ hơn nhiều. Nếu bạn cần một thứ hoạt động "độc đáo" với các thiết lập máy chủ phổ biến và với dịch vụ hỗ trợ ứng dụng web rộng lớn, thì WebSockets là lựa chọn tốt hơn ngay hôm nay.

WebTransport có giống như một UDP Socket API không?

Không. WebTransport không phải là UDP Socket API. Mặc dù WebTransport sử dụng HTTP/3, lần lượt sử dụng UDP "nâng cao", WebTransport có các yêu cầu đối với việc mã hoá và kiểm soát tắc nghẽn khiến nó có nhiều tính năng hơn so với API UDP Socket cơ bản.

WebTransport có phải là giải pháp thay thế cho kênh dữ liệu WebRTC không?

Có, đối với các kết nối máy khách-máy chủ. WebTransport có nhiều thuộc tính giống như kênh dữ liệu WebP, mặc dù các giao thức cơ bản là khác nhau.

Nhìn chung, việc chạy một máy chủ tương thích với HTTP/3 yêu cầu ít phải thiết lập và định cấu hình hơn so với việc duy trì máy chủ WebRTC. Điều này đòi hỏi bạn phải hiểu nhiều giao thức (ICE, DTLSSCTP) để có thể truyền tải hoạt động bình thường. WebRTC đòi hỏi nhiều yếu tố chuyển động hơn, có thể dẫn đến việc đàm phán với ứng dụng/máy chủ không thành công.

WebTransport API được thiết kế có lưu ý đến các trường hợp sử dụng của nhà phát triển web và sẽ cảm thấy giống như việc viết mã nền tảng web hiện đại hơn là sử dụng giao diện kênh dữ liệu của WebRTC. Không giống như WebRTC, WebTransport được hỗ trợ bên trong Web Workers, cho phép bạn thực hiện hoạt động giao tiếp máy chủ-máy khách độc lập với một trang HTML nhất định. Vì WebTransport hiển thị giao diện tuân thủ Luồng, nên WebTransport hỗ trợ tối ưu hoá đối với backpressure.

Tuy nhiên, nếu bạn đã có thiết lập máy khách/máy chủ WebRTC đang hoạt động mà bạn hài lòng, thì việc chuyển sang WebTransport có thể không mang lại nhiều lợi ích.

Dùng thử

Cách tốt nhất để thử nghiệm với WebTransport là khởi động một máy chủ HTTP/3 tương thích. Sau đó, bạn có thể sử dụng trang này với một ứng dụng JavaScript cơ bản để thử giao tiếp máy khách/máy chủ.

Ngoài ra, máy chủ tiếng vọng do cộng đồng duy trì cũng có sẵn tại webtransport.day.

Sử dụng API

WebTransport được thiết kế dựa trên nền tảng web hiện đại như API luồng. Tính năng này phụ thuộc rất nhiều vào lời hứa và hoạt động tốt với asyncawait.

Việc triển khai WebTransport hiện tại trong Chromium hỗ trợ ba loại lưu lượng truy cập riêng biệt: datagram cũng như cả luồng một chiều và hai chiều.

Kết nối với máy chủ

Bạn có thể kết nối với máy chủ HTTP/3 bằng cách tạo một thực thể WebTransport. Lược đồ của URL phải là https. Bạn cần chỉ định rõ số cổng.

Bạn nên sử dụng lời hứa ready để chờ thiết lập kết nối. Lời hứa này sẽ không được thực hiện cho đến khi thiết lập xong và sẽ từ chối nếu kết nối không thành công ở giai đoạn QUIC/TLS.

Lời hứa closed sẽ thực hiện khi kết nối đóng bình thường và từ chối nếu kết nối ngoài dự kiến.

Nếu máy chủ từ chối kết nối do lỗi chỉ báo ứng dụng (ví dụ: đường dẫn của URL không hợp lệ), thì điều đó sẽ khiến closed từ chối, còn ready vẫn chưa được giải quyết.

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 Datagram

Sau khi có một thực thể WebTransport được kết nối với một máy chủ, bạn có thể sử dụng thực thể đó để gửi và nhận các bit dữ liệu riêng biệt, gọi là datagram.

Phương thức getter writeable trả về một WritableStream mà ứng dụng web có thể dùng để gửi dữ liệu đến máy chủ. Phương thức getter readable trả về một ReadableStream, cho phép bạn nghe dữ liệu từ máy chủ. Cả hai luồng đều không đáng tin cậy, vì vậy có thể dữ liệu bạn ghi sẽ không được máy chủ nhận và ngược lại.

Cả hai loại luồng đều sử dụng các thực thể Uint8Array để chuyển dữ liệu.

// 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 luồng

Sau khi kết nối với máy chủ, bạn cũng có thể sử dụng WebTransport để gửi và nhận dữ liệu thông qua các API luồng.

Mỗi phần của tất cả các luồng là một Uint8Array. Không giống như API Datagram, các luồng này rất đáng tin cậy. Tuy nhiên, mỗi luồng đều độc lập với nhau, nên thứ tự dữ liệu trên các luồng không được đảm bảo.

WebTransportSendStream

Ứng dụng web tạo WebTransportSendStream bằng phương thức createUnidirectionalStream() của thực thể WebTransport. Phương thức này sẽ trả về một lời hứa cho WebTransportSendStream.

Sử dụng phương thức close() của WritableStreamDefaultWriter để đóng kết nối HTTP/3 được liên kết. Trình duyệt sẽ cố gắng gửi tất cả dữ liệu đang chờ xử lý trước khi thực sự đóng kết nối được liên kết.

// 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}`);
}

Tương tự, sử dụng phương thức abort() của WritableStreamDefaultWriter để gửi RESET\_STREAM đến máy chủ. Khi sử dụng abort(), trình duyệt có thể loại bỏ mọi dữ liệu đang chờ xử lý chưa được gửi.

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

Máy chủ khởi tạo một WebTransportReceiveStream. Việc nhận WebTransportReceiveStream là quá trình 2 bước cho ứng dụng web. Trước tiên, hàm này gọi thuộc tính incomingUnidirectionalStreams của một thực thể WebTransport để trả về một ReadableStream. Lần lượt, mỗi đoạn của ReadableStream đó là một WebTransportReceiveStream có thể dùng để đọc các phiên bản Uint8Array do máy chủ gửi.

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);
}

Bạn có thể phát hiện việc đóng luồng bằng cách sử dụng lệnh closed của ReadableStreamDefaultReader. Khi kết nối HTTP/3 cơ bản được đóng bằng bit FIN, lời hứa closed sẽ được thực hiện sau khi tất cả dữ liệu được đọc. Khi kết nối HTTP/3 đột ngột đóng (ví dụ: bằng RESET\_STREAM), lời hứa closed sẽ bị từ chối.

// 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 có thể do máy chủ hoặc ứng dụng tạo.

Ứng dụng web có thể tạo một thực thể web bằng cách sử dụng phương thức createBidirectionalStream() của một thực thể WebTransport. Phương thức này sẽ trả về một lời hứa cho một WebTransportBidirectionalStream.

const stream = await transport.createBidirectionalStream();
// stream is a WebTransportBidirectionalStream
// stream.readable is a ReadableStream
// stream.writable is a WritableStream

Bạn có thể theo dõi WebTransportBidirectionalStream do máy chủ tạo bằng thuộc tính incomingBidirectionalStreams của thực thể WebTransport. Thuộc tính này sẽ trả về ReadableStream. Mỗi phần của ReadableStream đó lần lượt là một 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 chỉ là sự kết hợp giữa WebTransportSendStreamWebTransportReceiveStream. Các ví dụ ở hai phần trước giải thích cách sử dụng từng hàm.

Ví dụ khác

Bản đặc tả bản nháp WebTransport bao gồm một số ví dụ bổ sung cùng dòng, cùng với tài liệu đầy đủ cho tất cả các phương thức và thuộc tính.

WebTransport trong Công cụ cho nhà phát triển của Chrome

Rất tiếc, Công cụ cho nhà phát triển của Chrome hiện không hỗ trợ WebTransport. Bạn có thể "gắn dấu sao" vấn đề này trên Chrome để được thông báo về nội dung cập nhật trên giao diện Công cụ cho nhà phát triển.

Vải polyfill

Một polyfill (hay đúng hơn là ponyfill) cung cấp chức năng như một mô-đun độc lập mà bạn có thể sử dụng) có tên là webtransport-ponyfill-websocket nhằm triển khai một số tính năng hiện có của WebTransport. Hãy đọc kỹ các điều kiện ràng buộc trong README của dự án để xác định xem giải pháp này có phù hợp với trường hợp sử dụng của bạn hay không.

Những điều cần cân nhắc về quyền riêng tư và bảo mật

Vui lòng xem phần tương ứng của bản quy cách nháp để nắm được hướng dẫn đáng tin cậy.

Ý kiến phản hồi

Nhóm Chrome muốn biết suy nghĩ và trải nghiệm của bạn khi sử dụng API này.

Phản hồi về thiết kế API

Có điều gì đó khó xử hoặc không hoạt động như mong đợi không? Hay có phần nào bị thiếu mà bạn cần triển khai ý tưởng không?

Gửi vấn đề trên kho lưu trữ Web Transport GitHub hoặc thêm ý kiến của bạn vào vấn đề hiện có.

Bạn gặp vấn đề khi triển khai?

Bạn có phát hiện thấy lỗi khi triển khai Chrome không?

Gửi lỗi tại https://new.crbug.com. Cung cấp càng nhiều thông tin chi tiết càng tốt, cùng với hướng dẫn đơn giản để tái tạo lỗi.

Bạn định sử dụng API?

Nội dung hỗ trợ công khai của bạn giúp Chrome ưu tiên các tính năng, đồng thời cho các nhà cung cấp trình duyệt khác biết tầm quan trọng của việc hỗ trợ họ.

  • Gửi một bài đăng trên Twitter tới @ChromiumDev kèm theo hashtag #WebTransport cùng thông tin chi tiết về vị trí và cách bạn sử dụng bài đăng này.

Thảo luận chung

Bạn có thể sử dụng web-transport-dev Google Group cho các câu hỏi hoặc vấn đề chung không thuộc một trong các danh mục khác.

Xác nhận

Bài viết này tổng hợp thông tin trong WebTransport Explainer (Tài liệu giải thích về WebTransport), thông số kỹ thuật nhápcác tài liệu thiết kế có liên quan. Cảm ơn các tác giả tương ứng đã cung cấp nền tảng đó.

Hình ảnh chính của bài đăng này là của Robin Pierre trên Unsplash.