Sử dụng WebTransport

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

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ành cho hoạt động giao tiếp hai chiều giữa ứng dụng web và máy chủ HTTP/3. API này hỗ trợ gửi dữ liệu một cách không đáng tin cậy thông qua API Datagram và một cách đáng tin cậy thông qua streams API.

Biểu đồ dữ liệu là lựa chọn lý tưởng để gửi và nhận dữ liệu không cần đảm bảo phân phối rõ ràng. Các gói dữ liệu riêng lẻ bị giới hạn về kích thước theo đơ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 được truyền. Nếu được chuyển đi, các gói dữ liệu này có thể đến theo thứ tự tuỳ ý. Những đặc điểm này làm cho API gói dữ liệu trở nên lý tưởng để truyền dữ liệu với độ trễ thấp và nỗ lực tối đa. Bạn có thể coi gói dữ liệu là thông báo giao thức gói dữ liệu người dùng (UDP) nhưng được mã hoá và kiểm soát tắc nghẽn.

Ngược lại, các API luồng cung cấp tính năng chuyển dữ liệu có thứ tự và đáng tin cậy. Các phương thức này phù hợp với các tình huống mà bạn cần gửi hoặc nhận một hoặc nhiều luồng dữ liệu có 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, nhưng vì HTTP/3 sử dụng giao thức QUIC nhẹ hơn nên bạn có thể mở và đóng các luồng này mà không hao tổn nhiều.

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

Đây là danh sách nhỏ các cách mà nhà phát triển có thể dùng WebTransport.

  • Gửi trạng thái trò chơi theo định kỳ với độ trễ tối thiểu tới máy chủ qua các thông báo nhỏ, không đáng tin cậy và không đúng thứ tự.
  • Nhận các luồng nội dung nghe nhìn đẩy từ mộ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 đẩy từ máy chủ trong khi trang web đang mở.

Chúng tôi muốn tìm hiểu 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

  • Chrome: 97.
  • Cạnh: 97.
  • Firefox: 114.
  • Safari: không được hỗ trợ.

Nguồn

Giống như tất cả tính năng không hỗ trợ trình duyệt chung, phương pháp hay nhất là viết mã theo cách phòng thủ 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 thông số kỹ thuật Hoàn tất
3. Thu thập ý kiến phản hồi và lặp lại thiết kế Hoàn thành
4. Bản dùng thử theo nguyên gốc Hoàn thành
5. Ra mắt Chromium 97

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

WebTransport có phải là 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à giao thức giao tiếp hợp lệ để sử dụng.

Hoạt động giao tiếp của WebSockets được mô hình hoá xung quanh một luồng thông báo duy nhất, đáng tin cậy và có thứ tự, phù hợp với một số loại nhu cầu giao tiếp. Nếu bạn cần các đặc điểm đó, thì các API luồng của WebTransport cũng có thể cung cấp chúng. So sánh, API datagram của WebTransport cung cấp 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, chúng không phải là giải pháp thay thế trực tiếp cho WebSockets.

Khi sử dụng WebTransport, thông qua các API gói dữ liệu hoặc qua nhiều phiên bản API Luồng dữ liệu đồng thời, bạn không cần phải lo lắng về việc chặn dòng đầu vì đây có thể là vấn đề xảy ra với WebSockets. Ngoài ra, việc thiết lập kết nối mới cũng mang lại nhiều lợi ích về hiệu suất, vì quá trình 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 thông số kỹ thuật nháp mới, do đó, hệ sinh thái WebSocket xung quanh thư viện ứng dụng và thư viện máy chủ hiện mạnh mẽ hơn nhiều. Nếu bạn cần một thiết bị nào đó hoạt động ngay từ đầu, với cách thiết lập máy chủ phổ biến và có hỗ trợ ứng dụng web trên diện rộng, WebSockets là lựa chọn tốt hơn hiện nay.

WebTransport có giống với 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 và sử dụng UDP " nâng cao", WebTransport có các yêu cầu về việc mã hoá và kiểm soát tắc nghẽn hơn so với một API UDP Socket cơ bản.

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

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

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

WebTransport API được thiết kế phù hợp với các trường hợp sử dụng của nhà phát triển web và sẽ giống như cách viết mã nền tảng web hiện đại thay vì 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 Trình chạy web, cho phép bạn thực hiện giao tiếp giữa máy khách và máy chủ độc lập với một trang HTML nhất định. Vì WebTransport có giao diện tuân thủ Streams, nên sẽ hỗ trợ các hoạt động tối ưu hoá cho hiệu suất.

Tuy nhiên, nếu bạn đã hài lòng với một chế độ thiết lập ứng dụng/máy chủ WebRTC đang hoạt độ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 ứng dụng JavaScript cơ bản để thử hoạt động giao tiếp giữa máy khách/máy chủ.

Ngoài ra, máy chủ lặp lại do cộng đồng duy trì có 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, chẳng hạn như Streams API. Tính năng này phụ thuộc rất nhiều vào hứa hẹn cũng như hoạt động hiệu quả 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: gói dữ liệu cũng như cả luồng một chiều và hai chiều.

Đang 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. Giao thứ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 quá trình thiết lập hoàn tất 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 việc đóng không mong muố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, trong khi 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 một thực thể WebTransport được kết nối với một máy chủ, bạn có thể dùng thực thể đó để gửi và nhận các bit dữ liệu riêng biệt, gọi là biểu đồ dữ liệu (datagram).

Phương thức getter writeable trả về một WritableStream mà ứng dụng web có thể sử 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 theo dõi dữ liệu từ máy chủ. Cả hai luồng vốn không đáng tin cậy nên có thể máy chủ sẽ không nhận được dữ liệu bạn ghi và ngược lại.

Cả hai loại luồng đều sử dụng 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 qua các API Luồng của nó.

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

WebTransportSendStream

WebTransportSendStream được ứng dụng web tạo bằng phương thức createUnidirectionalStream() của thực thể WebTransport. Phương thức này 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 đã liên kết. Trình duyệt sẽ tìm cách 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ý mà chưa được gửi đ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

WebTransportReceiveStream do máy chủ khởi tạo. Việc lấy WebTransportReceiveStream là quy trình 2 bước đối với ứng dụng web. Trước tiên, lệnh này gọi thuộc tính incomingUnidirectionalStreams của thực thể WebTransport và thực thể này trả về một ReadableStream. Mỗi phần của ReadableStream đó là một WebTransportReceiveStream có thể được dùng để đọc các thực thể 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 trạng thái đóng luồng bằng cách sử dụng lời hứa 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 bị đóng đột ngột (ví dụ: do RESET\_STREAM thực hiện), thì hứa hẹn 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.

Các ứng dụng web có thể tạo một đối tượng bằng phương thức createBidirectionalStream() của 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. Thực thể này sẽ trả về một ReadableStream. Mỗi phần trong ReadableStream đó lại 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 của WebTransportSendStreamWebTransportReceiveStream. Các ví dụ ở hai phần trước sẽ giải thích cách sử dụng từng phần.

Ví dụ khác

Thông số kỹ thuật nháp của WebTransport bao gồm một số ví dụ cùng dòng bổ sung, 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 của 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.

Ống 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 gọi là webtransport-ponyfill-websocket triển khai một số tính năng của WebTransport. Đọc kỹ các quy tắc 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

Hãy xem phần tương ứng của bản quy cách dự thảo để có hướng dẫn đáng tin cậy.

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ì đó khiến API bị lỗi hoặc không hoạt động như mong đợi không? Hay có thiếu phần nào mà bạn cần để triển khai ý tưởng của mình không?

Hãy báo cáo vấn đề trong kho lưu trữ GitHub về Web Transport hoặc nêu ý kiến về một vấn đề hiện có.

Bạn gặp vấn đề trong quá trình triển khai?

Bạn có phát hiện lỗi trong quá trình triển khai Chrome không?

Báo cáo 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 về cách tái tạo.

Dự định sử dụng API?

Sự 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 thấy tầm quan trọng của việc hỗ trợ các tính năng đó.

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

Thảo luận chung

Bạn có thể tham khảo nhóm Google Groups về giao thông vận tải web để trả lời các câu hỏi hoặc vấn đề chung không liên quan đến 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 từ WebTransport Explainer, quy cách nháptà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 trong bài đăng này là của Robin Pierre trên Unsplash.