Dùng Server-Sent Events trong Laravel để làm ứng dụng realtime
Vì sao Server-Sent Events là một phương pháp truyền tải dữ liệu realtime được ưa chuộng trong phát triển ứng dụng web và có gì khác biệt so với các phương pháp khác như WebSockets?
Trong bài viết này, chúng ta sẽ tìm hiểu về cách sử dụng Server-Sent Events trong Laravel, một trong những framework web phổ biến nhất hiện nay. Chúng ta sẽ cùng nhau tìm hiểu về SSE, cách cài đặt SSE trong Laravel, cách xây dựng ứng dụng SSE và những ưu nhược điểm của SSE để hiểu rõ hơn về công nghệ này và ứng dụng nó trong phát triển ứng dụng web.
1. Server-Sent Events (SSE) là gì?
Server-Sent Event (SSE)
Server-Sent Events (SSE) là một công nghệ truyền tải dữ liệu realtime từ server đến client thông qua HTTP protocol. Với SSE, server có thể gửi thông tin đến client mà không cần client gửi yêu cầu (request) trước đó. SSE được xem là một trong những phương pháp tiên tiến để tạo ra trải nghiệm người dùng tốt nhất và được ưa chuộng trong việc xây dựng ứng dụng web realtime như chat, notification hay live updates.
2. Tại sao nên sử dụng SSE trong ứng dụng web?
SSE cung cấp nhiều lợi ích cho việc xây dựng ứng dụng web realtime. Một số lợi ích của SSE như sau:
Bài viết này được đăng tại [free tuts .net]
- Không cần thiết lập kết nối mới cho mỗi request, giúp giảm tải cho server.
- Không cần sử dụng thư viện bên ngoài, SSE được hỗ trợ trực tiếp trong các trình duyệt hiện đại.
- SSE cho phép server gửi thông tin mới nhất tới client ngay khi nó có sẵn, giúp cập nhật thông tin realtime mà không cần phải tải lại trang.
- SSE là một giải pháp phù hợp cho các ứng dụng realtime như chat, notification hay live updates mà không cần phải sử dụng WebSockets.
Tóm lại, SSE là một phương pháp hiệu quả để truyền tải dữ liệu realtime trong ứng dụng web và cung cấp nhiều lợi ích cho việc xây dựng các ứng dụng realtime.
3. Cách sử dụng SSE trong Laravel
Cài đặt thư viện phía server
Để sử dụng SSE trong Laravel, ta cần cài đặt một số thư viện bổ sung. Trong trường hợp này, ta sẽ sử dụng thư viện Spatie\EventSourcing.
Bước 1: Sử dụng Composer để cài đặt thư viện Spatie\EventSourcing
.
composer require spatie/event-sourcing
Bước 2: Publish các file cấu hình của thư viện.
php artisan vendor:publish --provider="Spatie\EventSourcing\EventSourcingServiceProvider" --tag="config"
Cài đặt thư viện phía client
Để sử dụng SSE trên phía client, ta cần sử dụng JavaScript để lắng nghe sự kiện SSE. Thư viện EventSource
của HTML5 cung cấp các API để kết nối tới SSE.
Bước 1: Tạo một file JavaScript để kết nối tới SSE và lắng nghe sự kiện.
var source = new EventSource('/sse'); source.addEventListener('message', function(event) { console.log('Received message: ' + event.data); }); source.addEventListener('open', function(event) { console.log('Connected to SSE.'); }); source.addEventListener('error', function(event) { if (event.target.readyState === EventSource.CLOSED) { console.log('Disconnected from SSE.'); } else { console.log('Error occurred while connecting to SSE.'); } });
Bước 2: Thêm đoạn mã JavaScript vào file view của Laravel.
<script src="{{ asset('js/sse.js') }}"></script>
Tạo route SSE trong Laravel
Bước 1: Tạo một route trong file web.php
.
Route::get('/sse', function () { $response = new \Symfony\Component\HttpFoundation\StreamedResponse(function () { while (true) { echo "data: " . json_encode(['message' => 'Hello world']) . "\n\n"; ob_flush(); flush(); sleep(1); } }); $response->headers->set('Content-Type', 'text/event-stream'); $response->headers->set('Cache-Control', 'no-cache'); return $response; });
Trong ví dụ trên, route /sse sẽ trả về một response có kiểu text/event-stream và sử dụng phương thức StreamedResponse của Symfony để gửi dữ liệu realtime tới client. Trong hàm StreamedResponse
, ta sử dụng vòng lặp vô hạn để gửi thông tin realtime tới client. Trong ví dụ này, ta sẽ gửi một chuỗi JSON có nội dung {'message': 'Hello world'}
tới client sau mỗi giây.
Bước 2: Truy cập route /sse để kết nối tới SSE.
Sau khi đã cài đặt thư viện phía server và client, bây giờ ta có thể bắt đầu sử dụng Server-Sent Events trong Laravel.
Để tạo một SSE endpoint
, ta cần tạo một route trong file routes/web.php
. Ví dụ:
use App\Http\Controllers\SSEController; Route::get('/sse', [SSEController::class, 'stream'])->name('sse');
Trong đoạn code trên, ta đã tạo một route /sse
và liên kết nó với một action stream()
trong SSEController.
Trong SSEController, ta sẽ tạo một hàm stream()
để trả về response dạng SSE. Ví dụ:
namespace App\Http\Controllers; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\StreamedResponse; class SSEController extends Controller { public function stream(Request $request) { $response = new StreamedResponse(function () { // Các bước xử lý SSE }); $response->headers->set('Content-Type', 'text/event-stream'); $response->headers->set('Cache-Control', 'no-cache'); $response->headers->set('X-Accel-Buffering', 'no'); return $response; } }
Trong hàm stream()
, ta tạo một instance của StreamedResponse
để tạo ra response dạng SSE. Trong constructor của StreamedResponse,
ta truyền vào một closure để thực hiện các bước xử lý SSE.
Trong closure này, ta sẽ đầu tiên gửi một message SSE
bằng cách sử dụng thư viện php-redis
đã cài đặt ở bước trước đó:
use Illuminate\Support\Facades\Redis; Redis::publish('sse-channel', json_encode(['message' => 'Hello world!']));
Trong đoạn code trên, ta gửi một message SSE với nội dung là Hello world!
tới kênh sse-channel
bằng cách sử dụng Redis::publish()
.
Tiếp theo, ta sẽ thiết lập các header cho response dạng SSE bằng cách sử dụng các phương thức của đối tượng StreamedResponse
.
Sau khi đã tạo xong SSE endpoint, ta có thể sử dụng EventSource
để kết nối tới endpoint đó từ phía client và nhận các message SSE được gửi từ server. Ví dụ:
const source = new EventSource('/sse'); source.addEventListener('message', function(event) { console.log('Received SSE message: ' + event.data); });
Trong đoạn code trên, ta đã tạo một instance của EventSource
với địa chỉ là /sse
. Khi server gửi một message SSE tới endpoint
này, sự kiện message sẽ được kích hoạt và callback được định nghĩa trong hàm addEventListener()
sẽ được thực thi.
Sử dụng SSE trong Laravel
Sau khi đã cài đặt thư viện phía server và client, chúng ta có thể sử dụng SSE trong Laravel bằng cách tạo ra một route để xử lý yêu cầu SSE từ client. Để làm điều này, ta cần đăng ký một route trong file web.php
như sau:
Route::get('/sse', function () { return view('sse'); });
Trong đoạn code trên, chúng ta đã đăng ký một route có đường dẫn /sse
và trả về view sse.blade.php khi có yêu cầu từ client.
Tiếp theo, chúng ta sẽ tạo view sse.blade.php để xử lý SSE từ phía server. Đầu tiên, ta cần tạo ra một đối tượng Symfony\Component\HttpFoundation\StreamedResponse
để gửi response SSE cho client. Để làm điều này, ta sử dụng hàm response()->stream()
của Laravel như sau:
use Symfony\Component\HttpFoundation\StreamedResponse; return response()->stream(function () { $data = 'Hello, world!'; $event = 'message'; $id = '123'; echo "event: $event\n"; echo "id: $id\n"; echo "data: $data\n\n"; ob_flush(); flush(); }, 200, ['Content-Type' => 'text/event-stream']);
Trong đoạn code trên, chúng ta đã sử dụng hàm response()->stream()
để trả về một đối tượng StreamedResponse.
Đối số đầu tiên của hàm này là một closure để xử lý dữ liệu SSE cho client. Trong closure này, ta đã tạo ra ba biến $data
, $event
và $id
để định dạng SSE message. Sau đó, ta sử dụng các lệnh echo để gửi message SSE cho client. Lưu ý rằng chúng ta phải sử dụng ký tự xuống dòng \n\n
để đánh dấu kết thúc của một message SSE. Cuối cùng, ta sử dụng các hàm ob_flush() và flush()
để đảm bảo rằng response được gửi về client một cách liền mạch.
Tiếp theo, ta cần sử dụng JavaScript để nhận dữ liệu SSE từ phía server. Để làm điều này, ta sử dụng đoạn mã JavaScript sau:
const eventSource = new EventSource('/sse'); eventSource.addEventListener('message', (event) => { console.log(event.data); }); eventSource.addEventListener('error', (event) => { console.error('Server-Sent Event error:', event); });
Trong đoạn code trên, chúng ta đã tạo một đối tượng EventSource
để kết nối tới đường dẫn /sse
của server.
Tạo route SSE
Tiếp theo, bạn cần tạo một route SSE trong file web.php. Route này sẽ nhận các kết nối SSE từ client và trả về các sự kiện.
Trong ví dụ này, chúng ta sẽ tạo một route SSE tên là /sse
. Route này sẽ trả về các sự kiện đang diễn ra.
use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\StreamedResponse; Route::get('/sse', function (Request $request) { $response = new StreamedResponse(); $response->setCallback(function () { $data = ['message' => 'Hello, world!']; echo 'data: ' . json_encode($data) . PHP_EOL; echo PHP_EOL; ob_flush(); flush(); sleep(5); }); $response->headers->set('Content-Type', 'text/event-stream'); $response->headers->set('Cache-Control', 'no-cache'); return $response; });
Trong hàm callback, chúng ta đang trả về một message chứa đựng dữ liệu "Hello, world!". Để đảm bảo các sự kiện được trả về đến client một cách liên tục, chúng ta sử dụng hàm sleep để đợi 5 giây trước khi trả về kết quả tiếp theo.
Test ứng dụng
Bây giờ, chúng ta đã hoàn tất việc cài đặt SSE trong Laravel. Bạn có thể chạy ứng dụng và truy cập vào route /sse để kiểm tra các sự kiện được trả về từ server.
Để test SSE trong Laravel, bạn có thể sử dụng trình duyệt Chrome và công cụ Developer Tools để xem các sự kiện được trả về từ server.
4. Xây dựng ứng dụng SSE trong Laravel
Bước 1: Cài đặt package
Sử dụng composer để cài đặt package "laravel-sse" bằng cách chạy lệnh sau trong terminal:
composer require marchie/laravel-s
Bước 2: Thiết kế API SSE
Tạo một route trong file routes/web.php để xử lý kết nối SSE và gửi dữ liệu:
use Marchie\SSE\SSE; Route::get('/stream', function () { $sse = new SSE(); $sse->addEventListener('message', function () { $data = [ 'time' => date('H:i:s'), 'message' => 'Hello, SSE!' ]; return json_encode($data); }); $sse->start(); });
Trong ví dụ này, chúng ta tạo một SSE đơn giản gửi một tin nhắn "Hello, SSE!" cùng với thời gian hiện tại.
Bước 3: Tạo trang hiển thị thông tin realtime
Tạo một trang HTML để hiển thị thông tin realtime sử dụng SSE bằng cách đăng ký event listener cho object SSE. Trong ví dụ này, chúng ta sử dụng file resources/views/stream.blade.php
:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>SSE Demo</title> </head> <body> <h1>Realtime Messages</h1> <ul id="messages"></ul> <script> var source = new EventSource("/stream"); source.addEventListener('message', function(event) { var data = JSON.parse(event.data); var messages = document.getElementById("messages"); var li = document.createElement("li"); li.innerHTML = "[" + data.time + "] " + data.message; messages.appendChild(li); }); </script> </body> </html>
Trong trang HTML này, chúng ta sử dụng EventSource
để kết nối đến route SSE và đăng ký một event listener
để hiển thị dữ liệu realtime. Mỗi lần có một tin nhắn mới được gửi từ API SSE, chúng ta sẽ thêm nó vào danh sách hiển thị.
Bước 4: Tạo script javascript để kết nối tới API SSE và nhận thông tin realtime
Thêm script vào file resources/js/app.js
để kết nối đến API SSE và hiển thị dữ liệu realtime:
require('./bootstrap'); var source = new EventSource("/stream"); source.addEventListener('message', function(event) { var data = JSON.parse(event.data); console.log(data); });
Chúng ta sử dụng EventSource
để kết nối đến route SSE và đăng ký một event listener để hiển thị dữ liệu realtime trong console của trình duyệt.
Cập nhật file layout
Cuối cùng, chúng ta cần cập nhật file layout resources/views/layouts/app.blade.php
để sử dụng trang SSE và script javascript:
<!DOCTYPE html> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{{ config('app.name', 'Laravel') }}</title> <link rel="stylesheet" href="{{ mix('css/app.css') }}"> </head> <body> <div id="app"> @yield('content') </div> <script src="{{ mix('js/app.js') }}"></script> </body> </html>
Chúng ta thêm đoạn script <script src="{{ mix('js/app.js') }}"></script>
để kết nối tới API SSE.
Với các bước trên, bạn đã xây dựng xong ứng dụng SSE trong Laravel. Bây giờ, bạn có thể truy cập vào trang /stream để xem các tin nhắn realtime và kiểm tra console của trình duyệt để xem thông tin chi tiết.
5. Ưu điểm và nhược điểm của SSE
Ưu điểm của SSE
Realtime: SSE cho phép gửi dữ liệu từ server tới client trong thời gian thực, giúp các ứng dụng web hoạt động nhanh và hiệu quả hơn.
Dễ sử dụng: SSE là một giao thức đơn giản và dễ sử dụng, chỉ cần sử dụng một vài API của trình duyệt để kết nối tới server và nhận dữ liệu realtime.
Hiệu suất cao: SSE sử dụng kết nối HTTP đơn giản, giúp giảm thiểu tài nguyên mạng và tăng hiệu suất cho các ứng dụng web.
Hỗ trợ trình duyệt rộng rãi: SSE được hỗ trợ trên hầu hết các trình duyệt hiện đại, bao gồm cả trên thiết bị di động.
Dữ liệu có thể tuần tự: SSE cho phép gửi dữ liệu có thứ tự từ server tới client, giúp việc hiển thị thông tin trên giao diện người dùng dễ dàng hơn.
Nhược điểm của SSE
Không hỗ trợ truyền dữ liệu hai chiều: SSE chỉ cho phép truyền dữ liệu từ server tới client, không thể truyền dữ liệu ngược lại từ client tới server.
Chỉ hỗ trợ trình duyệt mới: SSE không được hỗ trợ trên các trình duyệt cũ, điều này có thể gây ra vấn đề về tương thích khi phát triển ứng dụng.
Thời gian delay có thể xảy ra: Mặc dù SSE là một giao thức realtime, thời gian delay có thể xảy ra trong trường hợp mạng bị chậm hoặc kết nối bị gián đoạn.
Giới hạn về số lượng kết nối: SSE không được thiết kế để xử lý hàng trăm hoặc hàng nghìn kết nối cùng lúc, điều này có thể gây ra vấn đề về hiệu suất và khả năng mở rộng của ứng dụng.
Kết bài viết
Trong kết luận, có thể khẳng định rằng việc sử dụng Server-Sent Events (SSE) trong Laravel là một lựa chọn tốt cho các lập trình viên muốn xây dựng các ứng dụng web realtime.
SSE cho phép truyền dữ liệu từ server tới client trong thời gian thực, giúp cải thiện hiệu suất và trải nghiệm người dùng của ứng dụng web. SSE cũng giúp giảm tải cho server bằng cách chỉ gửi dữ liệu khi cần thiết.
Trong Laravel, việc sử dụng SSE rất đơn giản nhờ vào package laravel-sse
, giúp chúng ta tiết kiệm thời gian và công sức trong việc xây dựng ứng dụng SSE. SSE cũng hỗ trợ trên hầu hết các trình duyệt hiện đại, đảm bảo tính tương thích và khả năng mở rộng cho ứng dụng.
Việc sử dụng SSE trong Laravel cho phép các lập trình viên xây dựng các ứng dụng web realtime tốt hơn, đáp ứng nhu cầu của người dùng và tạo ra trải nghiệm người dùng tốt hơn. Nó là một công nghệ quan trọng trong việc phát triển các ứng dụng web và có thể sẽ trở thành xu hướng phát triển trong tương lai.