Giới thiệu về Server Sent Events

Như các bạn đã biết về vấn đề push notification, hay tự động cập nhập dữ liệu, hoặc thông tin … trên website khá là phổ biến. Hôm nay tôi sẽ giới thiệu cho các bạn biết về một trong những kỹ thuật để thưc hiện tự động cập nhập dữ liệu web client đó là Server Sent Event

Như các bạn đã biết về vấn đề push notification, hay tự động cập nhập dữ liệu, hoặc thông tin … trên website khá là phổ biến. Hôm nay tôi sẽ giới thiệu cho các bạn biết về một trong những kỹ thuật để thưc hiện tự động cập nhập dữ liệu web client đó là Server Sent Event.

1. Giới thiệu về Server Sent Event

Vậy Server Sent Event là gì ?

Server-sent events (SSE) is a technology for a browser to get automatic updates from a server via HTTP connection. The Server-Sent Events EventSource API is standardized as part of HTML5 by the W3C. Về cơ bản  đây là một công nghệ của HTML5 giúp web client nhận dữ liệu từ máy chủ, sử dụng một kết nối (connection) trên máy chủ trong khoảng thời gian dài và gửi dữ liệu cho trình duyệt mà không đóng kết nối. Kỹ thuật này hữu ích trong việc cập nhập giá cả, tự đông cập nhập thông tin trên mạng xã hội, hay là push notification …

Một trong những kỹ thuật cũ để giải quyết vấn đề trên là Ajax Long Polling, kỹ thuật này cũng thực hiện việc cập nhập thường xuyên dữ liệu của web client bằng cách là thường xuyên gửi các yêu cầu (request) lên máy chủ (server) (Bằng việc khởi tạo đệ quy các request Ajax lên server). Nhưng trong quá trình này client sẽ phải khởi tạo các connection và đóng các connection liên tục, mà trong quá trình khởi tạo tạo các connection như thế thì client sẽ phải gửi các header lên máy chủ sau đó nhận dữ liệu về việc làm này sẽ khiến các request nặng hơn. Còn đối với kỹ thuật Server Sent Event thì chúng ta chỉ phải khởi tạo connection 1 lần và sau đó nhận dữ liệu từ server trả về mà không cân phải mở các kết nối tới máy chủ (Ở đây gần giông với websocket). Dưới đây là ví dụ về Ajax Long Polling:


(function poll(){
   setTimeout(function(){
      $.ajax({ url: "/path/to/url", success: function(data){
        console.log(data);  
        poll();
      }, dataType: "json"});
  }, 30000);
})();

Đây là đoạn javascript cho chúng ta thấy cách thực hiện cơ bản của Server Sent Event:


var es = new EventSource("/path/to/url"); 
es.addEventListener("message", function(e) { console.log(e.data); }, false);

Đoạn code script trên khởi tạo một đối tượng EventSource lắng nghe một url được chỉ định sẵn, và xử lý các dữ liệu mà máy chủ gửi lại cho web client. Mỗi lần có dữ liệu mới thì function callback sẽ được gọi và xử lý dữ liệu đó (Ở đọan code trên là console.log ra data gửi từ máy chủ về).

Đây là một kỹ thuật mới và tốt, nhưng không phải tất cả các trình duyệt đều hỗ trợ EventSource, Ảnh dưới đây cho chúng ta thấy những trình duyệt hỗ trợ EventSource

Selection_006

Ví dụ Server Sent Event

Để giới thiệu rõ ràng về vấn đề này sau đây tôi sẽ đưa ra một ví dụ của Server Sent Event trong việc push notification trong laravel 5.2

Đầu tiên tôi sẽ khai báo một routes:


Route::get('/notification/get-new-notification', 'NotificationController@getNewNotification');

Sau đó tôi sẽ khai báo đoạn code script để thực hiện get new notification từ client như sau:


if (typeof(EventSource) !== "undefined") {
   var notification = new EventSource('/notification/get-new-notification');
   notification.onmessage = function (event) {
   var data = JSON.parse(event.data);
   //doing something
   }
} else {
   (function poll(){
    setTimeout(function(){
        $.ajax({ url: "/notification/get_notification", success: function(data){ 
        //doing something
        poll();
        }, dataType: "json"});
    }, 3000);
    })();
}

Ở đoạn code trên có cả việc kiểm tra xem trình duyệt có hỗ trợ EventSource hay không. Nếu không có chúng ta sẽ quay về thực hiện kỹ thuật cũ là Ajax Long Polling.
Sau đó tôi khai báo hàm getNewNotification() trong NotificationController để thực hiện việc push dữ liệu từ server lên client


$response = new StreamedResponse();
        $response->headers->set('Content-Type', 'text/event-stream');
        $response->headers->set('Cache-Control', 'no-cache');
        $response->setCallback(function (){
           try{
                $notifications = $this->getNotification();
                $data =[
                    "status" => Consts::STATUS_OK,
                    'data' => $notifications,
                ];
            }catch (Exception $e){
                $data =[
                    "status" => Consts::STATUS_ERROR,
                    "error" => ["message" => $e->getMessage()]
                ];
            }
            echo 'data: ' . json_encode($data) . "\n\n";

            ob_flush();
            flush();
            sleep(3);
        });
        $response->send();

Giải thích:

  1. Content type của các response là text/event-stream.
  2. Thiết lập sao cho trình duyệt không lưu cache
  3. $response->send() Cho phép gửi dữ liệu từ máy chủ lên web client theo dạng khôi dự liệu. Và $response->send(); chấp nhập việc gọi hàm Callback để chuyển giao các dữ liệu
  4. Các dữ liệu trả về là tiền tố với “data” và thêm “\ n \ n” vào cuối dòng
  5. flush () và ob_flush () được gọi để kích hoạt việc gửi dữ liệu trở lại trình duyệt.
  6. sleep(3) sẽ giúp cho quá trình gửi dữ liệu từ server lên client 3 giây một lần

Sau khi chạy chương trình, thì cứ 3s bạn sẽ nhận được dữ liệu từ server gửi về client. Và việc nhận dữ liệu này sẽ kết thúc khi bạn đóng trình duyệt
Tài liệu tham khảo: http://zrashwani.com/server-sent-events-example-laravel/#.V_tqLHV97CK
P/s: Chú ý trong tài liệu tham khảo trên , đoạn code từ server để push dữ liệu lên client có sử dụng while(true) điều này sẽ khiên server của bạn bị treo.