WebTransport là một API cung cấp dịch vụ nhắn tin hai chiều, độ trễ thấp giữa máy khách và máy 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. Đây là giao thức dành cho giao tiếp hai chiều giữa một ứng dụng web và một máy chủ HTTP/3. Nó hỗ trợ gửi dữ liệu không đáng tin cậy thông qua API datagram và đáng tin cậy thông qua API luồng.
Datagram là lựa chọn lý tưởng để gửi và nhận dữ liệu không cần đảm bảo việc gửi. Kích thước của từng gói dữ liệu bị giới hạn bởi đơn vị truyền tối đa (MTU) của kết nối cơ bản, có thể truyền thành công hoặc không, và nếu được truyền, chúng có thể đến theo thứ tự bất kỳ. Những đặc điểm này khiến API datagram trở nên lý tưởng cho việc truyền dữ liệu có độ trễ thấp và nỗ lực tối đa. Bạn có thể coi các gói dữ liệu là thông báo giao thức dữ liệu người dùng (UDP), nhưng được mã hoá và kiểm soát tình trạng tắc nghẽn.
Ngược lại, các API luồng cung cấp hoạt động truyền dữ liệu đáng tin cậy và có thứ tự. Chúng rất phù hợp với những trường hợp 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 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 có trọng lượng nhẹ hơn ở bên dưới, nên các kết nối này có thể được mở và đóng mà không tốn nhiều chi phí.
Trường hợp sử dụng
Đây là một danh sách nhỏ về những cách mà nhà phát triển có thể sử dụng WebTransport.
- Gửi trạng thái trò chơi theo một khoảng thời gian đều đặn với độ trễ tối thiểu đến một máy chủ thông qua các thông báo nhỏ, không đáng tin cậy và không theo thứ tự.
- Nhận luồng nội dung nghe nhìn được truyền 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 gửi từ một máy chủ trong khi một trang web đang mở.
Chúng tôi rất mong được biết thêm về cách bạn dự định sử dụng WebTransport.
Hỗ trợ trình duyệt
Giống như mọi tính năng không được trình duyệt hỗ trợ trên diện rộng, việc viết mã phòng thủ thông qua phát hiện tính năng là một phương pháp hay.
Trạng thái hiện tại
Bước | Trạng thái |
---|---|
1. Tạo video 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. Ra mắt | Chromium 97 |
Mối quan hệ của WebTransport với các công nghệ khác
WebTransport có thay thế cho WebSocket 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 WebSockets được mô hình hoá dựa trên 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 những đặc điểm đó, thì các API luồng của WebTransport cũng có thể cung cấp chúng. Ngược lại, các API datagram của WebTransport cung cấp khả năng phân phối có độ trễ thấp, không đảm bảo độ 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 WebSocket.
Khi sử dụng WebTransport thông qua các API datagram hoặc thông qua nhiều phiên bản Streams API đồng thời, bạn không phải lo lắng về tình trạng chặn đầu dòng. Đây có thể là một vấn đề với WebSocket. Ngoài ra, việc thiết lập các kết nối mới cũng mang lại lợi ích về hiệu suất, vì cái 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 bản nháp đặc tả mới. Do đó, hệ sinh thái WebSocket xung quanh các thư viện máy 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 "ngay lập tức" với các chế độ thiết lập máy chủ thông thường và có khả năng hỗ trợ rộng rãi cho máy khách web, thì WebSockets là lựa chọn phù hợp hơn hiện nay.
WebTransport có giống với UDP Socket API không?
Không. WebTransport không phải là một UDP Socket API. Mặc dù WebTransport sử dụng HTTP/3, đến lượt HTTP/3 sử dụng UDP "ngầm", nhưng WebTransport có các yêu cầu về việc mã hoá và kiểm soát tình trạng tắc nghẽn, khiến WebTransport trở thành một API Ổ cắm UDP cơ bản.
WebTransport có phải là một lựa chọn thay thế cho các 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ư các kênh dữ liệu WebRTC, 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 đòi hỏi ít bước thiết lập và cấu hình hơn so với việc duy trì một máy chủ WebRTC. Việc này liên quan đến việc tìm hiểu nhiều giao thức (ICE, DTLS và SCTP) để có được một phương thức truyền tải hoạt động. WebRTC bao gồm nhiều thành phần chuyển động hơn có thể dẫn đến việc thương lượng không thành công giữa máy khách và máy chủ.
WebTransport API được thiết kế dựa trên các trường hợp sử dụng của nhà phát triển web và có cảm giác giống như viết mã nền tảng web hiện đại hơn là sử dụng các giao diện kênh dữ liệu của WebRTC. Không giống như WebRTC, WebTransport được hỗ trợ trong Web Worker, 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 hiển thị một giao diện tuân thủ Streams, nên giao diện này hỗ trợ các hoạt động tối ưu hoá xung quanh áp suất ngược.
Tuy nhiên, nếu bạn đã có một chế độ 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 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 để dùng thử hoạt động giao tiếp giữa ứng dụng và máy chủ.
Ngoài ra, bạn có thể truy cập vào một máy chủ lặp lại do cộng đồng duy trì tại webtransport.day.
Sử dụng API
WebTransport được thiết kế dựa trên các nguyên tắc cơ bản của nền tảng web hiện đại, chẳng hạn như Streams API. Nó phụ thuộc nhiều vào promise và hoạt động tốt với async
và await
.
Chế độ triển khai WebTransport hiện tại trong Chromium hỗ trợ 3 loại lưu lượng truy cập riêng biệt: datagram, cũng như cả luồng đơn hướng và luồng hai chiều.
Kết nối với máy chủ
Bạn có thể kết nối với một máy chủ HTTP/3 bằng cách tạo một phiên bản WebTransport
. Lược đồ của URL phải là https
. Bạn cần chỉ định rõ ràng 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ệnh 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 kết nối diễn ra bất ngờ.
Nếu máy chủ từ chối kết nối do lỗi chỉ báo của ứ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 phân giải.
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.t>hen(() = {
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
Sau khi có một phiên bản WebTransport được kết nối với một máy chủ, bạn có thể dùng phiên bản đó để gửi và nhận các bit dữ liệu riêng biệt, còn gọi là datagram.
Phương thức truy xuất writeable
trả về 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 vốn 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 này đề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);
}
Streams API
Sau khi kết nối với máy chủ, bạn cũng có thể dùng WebTransport để gửi và nhận dữ liệu thông qua Streams API.
Mỗi khối của tất cả các luồng là một Uint8Array
. Không giống như Datagram API, các luồng này đáng tin cậy. Tuy nhiên, mỗi luồng đều độc lập, nên không đảm bảo thứ tự dữ liệu giữa các luồng.
WebTransportSendStream
WebTransportSendStream
được ứng dụng web tạo bằng phương thức createUnidirectionalStream()
của một 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 luồng 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 luồng 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: ${erro
r}`);
}
Tương tự, hãy 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ột WebTransportReceiveStream
do máy chủ khởi tạo. Việc lấy WebTransportReceiveStream
là quy trình gồm hai bước đối với một ứng dụng web. Trước tiên, phương thức này gọi thuộc tính incomingUnidirectionalStreams
của một thực thể WebTransport
, trả về một ReadableStream
. Mỗi đoạn ReadableStream
đó lần lượt là một WebTransportReceiveStream
có thể 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 luồng HTTP/3 cơ bản đóng bằng bit FIN, lời hứa closed
sẽ được thực hiện sau khi đọc tất cả dữ liệu. Khi luồng HTTP/3 bị đóng đột ngột (ví dụ: bằng RESET_STREAM
), thì 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.');
}).ca>tch(() = {
console.error('The receiveStream closed abrup
tly.');
});
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 ứng dụng bằng phương thức createBidirectionalStream()
của một phiên bản WebTransport
. Phương thức này sẽ trả về một lời hứa cho 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 một WebTransportBidirectionalStream
do máy chủ tạo bằng thuộc tính incomingBidirectionalStreams
của một phiên bản WebTransport
. Thuộc tính này sẽ trả về một ReadableStream
. Mỗi khối 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 WebTransportSendStream
và WebTransportReceiveStream
. Các ví dụ trong hai phần trước giải thích cách sử dụng từng phương thức.
Ví dụ khác
Bản đặc tả nháp WebTransport bao gồm một số ví dụ nội tuyến 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 trên Chrome để nhận thông báo về các bản cập nhật đối với giao diện DevTools.
Polyfill
Có một polyfill (hoặc đúng hơn là ponyfill cung cấp chức năng dưới dạng một mô-đun độc lập mà bạn có thể sử dụng) có tên là webtransport-ponyfill-websocket
. Polyfill này triển khai một số tính năng của WebTransport. Hãy đọc kỹ cá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 trong bản quy cách nháp để biết hướng dẫn chính thức.
Phản hồi
Nhóm Chrome muốn biết ý kiến và trải nghiệm của bạn khi sử dụng API này.
Ý kiến phản hồi về thiết kế API
Có điều gì bất tiện hoặc không hoạt động như mong đợi về API không? Hay bạn còn thiếu những yếu tố cần thiết để triển khai ý tưởng của mình?
Báo cáo vấn đề trên kho lưu trữ Web Transport GitHub hoặc thêm ý kiến của bạn vào một 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 trong quá trình triển khai của 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 để tái hiện lỗi.
Bạn đang lên kế hoạch sử dụng API này?
Sự ủng hộ công khai của bạn giúp Chrome ưu tiên các tính năng và 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 này.
- Gửi một tweet đến @ChromiumDev bằng thẻ bắt đầu bằng
#WebTransport
và thông tin chi tiết về nơi và cách bạn sử dụng.
Thảo luận chung
Bạn có thể sử dụng Nhóm Google web-transport-dev 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.
Lời cảm ơn
Bài viết này kết hợp thông tin từ WebTransport Explainer, bản nháp quy cách và cá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 trong bài đăng này là của Robin Pierre trên Unsplash.