Server Sent Event in Rails

Dạo đầu

    Ngày ni tui học về cách nhận data từ server mà không cần reload web page

    Một vài cách mà tui nghe giang hồ đồn:

  • HTTP long-polling: Client gửi 1 request đến server và chờ sau một khoảng nhất định hoặc đến khi nhận được phản hồi và đóng lại.
  • Webhooks: Khi nào server cập nhật thì nó sẽ request đến client, nhưng yêu cầu client phải chạy http server
  • Server-Sent Events: Sau request đầu tiền từ client đến server thì kết nối 1 chiều được duy trì, khi nào server có gì mới sẽ đẩy về cho client (Xem thêm ở đây)
  • WebSockets: Cũng tương tự như Server-Sent Events nhưng duy trì kết nối 2 chiều qua lại client <=> server

    Tùy yêu cầu từng ứng dụng để chọn phương pháp hợp lí. Ví dụ làm web cập nhật thời tiết theo thời gian thực thì client chỉ cần nhận dữ liệu từ server trong trường hợp ni tui dùng SSE, còn web chat gì đó vừa gửi request, vừa nhận data thì tui dùng WebSockets

Vô bài!!!

Server

    Controller

class CommentsController < ApplicationController
  include ActionController::Live

  def progress
    sse = SSE.new(response.stream)
    response.headers['Content-Type'] = 'text/event-stream'
    5.times do |i|
      sse.write({count: i}.to_json)
    end
  rescue IOError
    # code
  ensure
    sse.close
  end
end

    Và Route

get 'comments/progress', to: 'comments#progress'

Client

    Tui dùng javascript để xử lí data server gửi về

var div = document.getElementById('divID');
var sse = new EventSource('/comments/progress');
sse.addEventListener('message', function (e) {
  div.innerHTML += e.data;
});

Thành quả

    

    Để rõ hơn, bật devtool lên, xong vô network tab > EventStream tui chộ có 1 kết nối tên là process hiển thị những data server gửi về

Dùng redis để cool ngầu hơn

    Trong Create action tui lưu những comment vào channel có tên là comment:progress. Sau đó ở process action, bằng cách subcribe channel comment:progress để lấy ra khi có thằng comment vừa được lưu vào

class CommentsController < ApplicationController
  include ActionController::Live

  def progress
    redis = Redis.new
    sse   = SSE.new(response.stream)
    response.headers['Content-Type'] = 'text/event-stream'
    redis.subscribe('comment:progress') do |on|
      on.message { |e, data| sse.write(data) }
    end
  rescue IOError
      # code
  ensure
    redis.quit
    sse.close
  end
  
  def create
    redis = Redis.new
    redis.publish('comment:progress', {count: i}.to_json)
  end
end

Như rứa là tui đã setup xong SSE cơ bản rồi

Nguồn: Viblo

Bình luận
Vui lòng đăng nhập để bình luận
Một số bài viết liên quan