🌞

Gửi message từ server nhưng không dùng WebSocket

Sửa bài viết này

Nếu cần gửi một message từ server đến client, thay vì phía client gửi request tới server, Javascript có một cơ chế đã được hỗ trợ từ rất lâu, là dùng EventSource, nó còn có trước khi có WebSocket. Tất nhiên nó cũng những hạn chế nhất định so với WebSocket. Cụ thể

WebSocket EventSource
Hai chiều Một chiều từ server
Binary và text Chỉ text
WebSocket Protocal HTTP

EventSource là một lựa chọn phù hợp cho những trường hợp đơn giản, chưa cần dùng đến đao to búa lớn như WebSocket. Ví dụ giá vàng, giá xăng cần cập nhập, những dữ liệu mà chỉ cần đi một chiều từ server -> client. EventSource còn hỗ trợ auto-reconnect cũng rất tiện (WebSocket phải chạy bằng cơm)

Nhận message

Để nhận một message, chúng ta cần tạo một instance new EventSource(url), trình duyệt tự quản lý thiết lập kết nối đến url và lắng nghe các event gửi đến.

Server sẽ trả về status 200 và header Content-Type: text/event-stream, message được gửi đến sẽ theo định dạng cố định

data: Message 1

data: Message 2

data: Message 3
data: dòng 2 của Message 3

Nội dung sẽ nằm sau từ khóa data:, các message sẽ được tách biệt bằng 2 dấu xuống dòng \n\n, nếu chỉ có một dấu \n có nghĩa là message này gồm 2 dòng.

Trong thực tế, không nên tách message ra 2 dòng và luôn gửi message theo một dòng duy nhất

data:  {"user":"John","message":"First line_\n_ Second line"}

Để đọc message này

let eventSource = new EventSource("/events/subscribe");

eventSource.onmessage = function(event) {
  console.log("New message", event.data);
};

// hoặc eventSource.addEventListener('message', ...)

Cross-origin request

Tương tự như fetch, chúng ta có thể lắng nghe trên một message cross-origin

let source = new EventSource("https://another-site.com/events");

Để gửi thêm thông tin credential

let source = new EventSource("https://another-site.com/events", {
  withCredentials: true
});

Reconnect

Như đã nói, EventSource tự động reconnect nếu bị đứt connection giữa chừng, server cũng có thể thông báo nên chờ bao lâu trước khi thử lại bằng retry:

retry: 15000
data: Hello, I set the reconnection delay to 15 seconds

Nếu server không muốn trình duyệt tự động reconnect, server có thể trả status 204, hoặc ở phía client chúng ta cưỡng chế luôn eventSource.close()

Message Id

Để giải quyết vấn đề mất message giữa chừng do lỗi connect và không biết được message nào đã nhận và chưa, mỗi message có thể có thêm field id để dễ xác định

data: Message 1
id: 1

data: Message 2
id: 2

data: Message 3
data: of two lines
id: 3

Connection Status

Bên trong object EventSource sẽ có property readyState, nó chứa status của connection

  • EventSource.CONNECTING = 0
  • EventSource.OPEN = 1
  • EventSource.CLOSED = 2

Event type

Có 3 loại event có thể được gửi về từ EventSource

  • message: khi có message gửi về
  • open: khi connection đã open
  • error: lỗi không thể connect đến server

Server cũng có thể gửi thêm các kiểu event tự định nghĩa khác ngoài các event có sẵn

event: join
data: Bob

data: Hello

event: leave
data: Bob

Để lắng nghe những custom event như vậy

eventSource.addEventListener('join', event => {
  alert(`Joined ${event.data}`);
});

eventSource.addEventListener('message', event => {
  alert(`Said: ${event.data}`);
});

eventSource.addEventListener('leave', event => {
  alert(`Left ${event.data}`);
});

https://javascript.info/

Initializing...