Bạn muốn ứng dụng của mình có tính năng thông báo (notification) real-time và hiệu quả? Hướng dẫn này sẽ giúp bạn xây dựng một server Socket.IO mạnh mẽ và đáng tin cậy để xử lý mọi loại thông báo, từ cập nhật trạng thái đơn giản đến những cảnh báo quan trọng. Chúng ta sẽ đi sâu vào cách thiết lập server, quản lý kết nối từ client, và triển khai các sự kiện để gửi thông báo tức thời, đảm bảo người dùng luôn nhận được thông tin một cách nhanh chóng và chính xác nhất.
Bài viết này sẽ hướng dẫn bạn cách xây dựng hệ thống thông báo realtime trong ứng dụng Laravel sử dụng Socket.IO và Redis, giúp nâng cao trải nghiệm người dùng bằng cách cung cấp thông tin tức thì.
Để bắt đầu, chúng ta cần thiết lập một server Socket.IO để xử lý các kết nối realtime.
Bạn cần cài đặt hai gói thư viện quan trọng: socket.io
(cho server realtime) và ioredis
(để kết nối với Redis). Chạy lệnh sau trong terminal của bạn:
npm install socket.io ioredis
Tạo một file JavaScript (ví dụ: server.js
) và thêm đoạn code sau để khởi tạo server Socket.IO:
const io = require('socket.io')(6001);
console.log('Connected to port 6001');
io.on('error', function(socket) {
console.log('error');
});
io.on('connection', function(socket) {
console.log('Co nguoi vua ket noi: ' + socket.id);
});
const Redis = require('ioredis');
const redis = new Redis(6379);
redis.psubscribe("*", function(error, count) {
console.log('Subscribed to ' + count + ' channels');
});
redis.on('pmessage', function(partner, channel, message) {
console.log('--- New message from Redis ---');
console.log('Channel: ' + channel);
console.log('Message: ' + message);
console.log('Partner: ' + partner);
try {
message = JSON.parse(message);
io.emit(channel + ":" + message.event, message.data.message);
console.log('Sent to client: ' + channel + ":" + message.event);
} catch (e) {
console.error('Failed to parse message or emit to client:', e);
}
});
Giải thích:
const io = require('socket.io')(6001)
: Khởi tạo Socket.IO server và lắng nghe trên cổng 6001.io.on('connection', ...)
: Lắng nghe sự kiện khi có client kết nối thành công.const redis = new Redis(6379)
: Kết nối đến Redis server trên cổng 6379.redis.psubscribe("*", ...)
: Đăng ký lắng nghe tất cả các channel trong Redis. Điều này cho phép server Socket.IO nhận được bất kỳ tin nhắn nào được publish lên Redis.redis.on('pmessage', ...)
: Khi có một tin nhắn mới được publish lên Redis, sự kiện này sẽ được kích hoạt. Tin nhắn sẽ được parse từ JSON và phát đi (emit) đến tất cả các client đã kết nối thông qua Socket.IO.Để Redis server có thể hoạt động và cho phép kết nối từ xa (nếu cần), bạn cần cấu hình file redis.conf
.
/etc/redis/redis.conf
hoặc /usr/local/etc/redis.conf
tùy thuộc vào hệ điều hành và cách cài đặt của bạn.bind 127.0.0.1
và thay đổi thành bind 0.0.0.0
để cho phép kết nối từ tất cả các địa chỉ IP, hoặc comment dòng này đi (# bind 127.0.0.1
). Lưu ý: Việc mở rộng bind
ra 0.0.0.0
có thể tạo ra lỗ hổng bảo mật nếu Redis không được bảo vệ bằng mật khẩu.# requirepass foobared
và bỏ comment, sau đó thay foobared
bằng mật khẩu của bạn.sudo systemctl restart redis
hoặc sudo service redis restart
.Bây giờ, chúng ta sẽ cấu hình ứng dụng Laravel để có thể gửi các thông báo đến Redis, từ đó được Socket.IO server nhận và phát đi.
Laravel sử dụng gói predis/predis
để tương tác với Redis. Cài đặt nó bằng Composer:
composer require predis/predis
.env
và config/database.php
Mở file .env
trong thư mục gốc của dự án Laravel và cập nhật các biến môi trường sau:
BROADCAST_DRIVER=redis
CACHE_DRIVER=redis
FILESYSTEM_DRIVER=local
QUEUE_CONNECTION=redis
SESSION_DRIVER=redis
SESSION_LIFETIME=120
MEMCACHED_HOST=127.0.0.1
REDIS_HOST=125.212.243.160 # Thay bằng IP của server Redis của bạn
REDIS_PASSWORD=null # Điền mật khẩu nếu có
REDIS_PORT=6379
REDIS_PREFIX="" # Có thể để trống hoặc đặt prefix nếu muốn
Giải thích:
BROADCAST_DRIVER=redis
: Cấu hình Laravel sử dụng Redis làm driver broadcast, cho phép gửi các sự kiện realtime qua Redis.REDIS_HOST
, REDIS_PASSWORD
, REDIS_PORT
: Thông tin kết nối đến Redis server. Đảm bảo REDIS_HOST
trỏ đúng đến địa chỉ IP của server Redis mà bạn đã cấu hình ở phần I.Bạn cũng có thể kiểm tra file config/database.php
để đảm bảo phần cấu hình Redis đã được thiết lập đúng, thường nó sẽ tự động nhận từ các biến môi trường trong .env
.
Để dễ dàng kiểm thử việc gửi thông báo, bạn có thể tạo một Artisan Command.
Lệnh tạo command:
php artisan make:command SendRealtimeNotification
Nội dung file command (app/Console/Commands/SendRealtimeNotification.php
):
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis; // Import Redis Facade
class SendRealtimeNotification extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'notify:realtime {message}'; // Thêm {message} để nhận đối số
/**
* The console command description.
*
* @var string
*/
protected $description = 'Send a realtime notification via Redis and Socket.IO';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$messageData = [
'event' => 'new-message', // Tên sự kiện bạn muốn phát đi
'data' => [
'message' => $this->argument('message') // Lấy thông điệp từ đối số command
]
];
// Publish tin nhắn lên Redis channel 'test-channel'
Redis::publish('test-channel', json_encode($messageData));
$this->info('Realtime notification sent successfully!');
return Command::SUCCESS;
}
}
Đăng ký command:
Bạn không cần đăng ký thủ công nếu bạn đã tạo command bằng Artisan, Laravel sẽ tự động phát hiện nó. Để kiểm tra, chạy php artisan list
và tìm tên command của bạn.
Bất cứ nơi nào trong mã PHP của bạn (ví dụ: trong controller, service, model), bạn có thể sử dụng đoạn code sau để gửi thông báo realtime:
use Illuminate\Support\Facades\Redis;
// ...
$dataToSend = [
'user_id' => 1,
'notification_content' => 'Chào mừng bạn đến với hệ thống!',
'timestamp' => now()->toDateTimeString()
];
// Publish dữ liệu lên một channel của Redis
// 'my-channel' là tên channel. Bạn có thể thay đổi tùy ý.
// 'new-event' là tên sự kiện bên trong channel.
Redis::publish('my-channel', json_encode([
'event' => 'new-event',
'data' => [
'message' => $dataToSend
]
]));
Lưu ý quan trọng:
my-channel
: Đây là tên channel mà Socket.IO server của bạn sẽ lắng nghe.new-event
: Đây là tên của sự kiện bên trong channel đó. Khi Socket.IO nhận được tin nhắn, nó sẽ emit sự kiện dưới dạng my-channel:new-event
.$dataToSend
: Đây là dữ liệu thực tế bạn muốn gửi. Đảm bảo dữ liệu này được đặt trong một mảng và được mã hóa thành JSON.
node server.js
Bạn sẽ thấy thông báo "Connected to port 6001".php artisan notify:realtime "Hello from Laravel!"
Redis::publish
.Bạn sẽ thấy tin nhắn được in ra trong terminal của Socket.IO server, cho thấy nó đã nhận được tin nhắn từ Redis và đã emit đến các client.