Quay lại
Cách sử dụng Laravel WebSockets

Hi 500 anh em , hôm nay mình sẽ hướng dẫn cách dùng websockets trong laravel, với những dự án mình làm thực tế trước đây thì cũng đã sử dụng websockets để áp dụng cho những website có ứng dụng chat , gửi thông báo , hay là 1 trang xã hội tương tác thời gian thực...Thì hôm nay mình lại được làm 1 dự án ERP với chức năng timer để tính thời gian cho 1 khối lượng công việc trong team, mình thấy cũng khá hay nên hôm nay có time thì viết luôn 1 bài về thằng websockets này , OK bắt đầu thôi nào .

Giới thiệu

Trong bài hướng dẫn này chúng ta sẽ sử dụng laravel websockets package nó là một sự thay thế tuyệt vời cho Pusher.

Với package WebSockets của Laravel thì nó giả lập API Pusher và cho phép bạn dễ dàng kết nối với máy chủ WebSockets và đăng ký kênh, giống như bạn làm với Pusher.

Cách tốt nhất để sử dụng gói Laravel WebSockets này là thay thế trực tiếp cho Pusher.

Cài đặt Laravel WebSockets

Để cài đặt gói Laravel WebSockets, bạn cần chạy lệnh sau:

composer require beyondcode/laravel-websockets

Note: Trong trường hợp bạn dùng laravel 9 trờ lên thì chạy cmd sau không có nó sẽ báo lỗi dependencies nè :

composer require beyondcode/laravel-websockets:^1.14 -W

- W : Sử dụng tùy chọn --with-all-dependencies (-W) để cho phép nâng cấp, hạ cấp và xóa đối với các gói hiện bị khóa đối với các phiên bản cụ thể.

Sau đó, bạn phải publish migration file bằng cách chạy lệnh sau:

php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="migrations"

Command ở trên sẽ publish migration file vào thư mục database/migrations của ứng dụng của bạn. Quá trình migration của WebSockets sẽ định nghĩa và lưu trữ một bảng của WebSockets sinh ra và chứa một số thống kê về các sự kiện WebSockets.

Trước khi chạy lệnh migration bên dưới, bạn cần đảm bảo rằng bạn đã định cấu hình cơ sở dữ liệu trong tệp .env của mình. Sau đó, bạn có thể chạy lệnh migration:

php artisan migrate

Tiếp theo, bạn cũng cần publish tệp cấu hình của WebSockets bằng cách chạy lệnh sau:

php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="config"

Ở trên publish tệp cấu hình WebSockets vào tệp config/websockets.php của ứng dụng của bạn. Trong đó, bạn có thể cấu hình và cài đặt máy chủ WebSockets. Để biết thêm thông tin về tệp cấu hình, bạn có thể đọc thêm về document để biết thêm nhé.

Cấu hình Laravel WebSockets 

Vì gói WebSockets hoàn toàn tương thích với Pusher nên chúng ta có thể sử dụng cùng một cấu hình như chúng ta sử dụng cho Pusher.

Vì vậy, để cài đặt gói Pusher, bạn cần chạy lệnh sau:

composer require pusher/pusher-php-server "~3.0"
or
composer require pusher/pusher-php-server:^7.0

Trong tệp .env của bạn, hãy thay đổi BROADCAST_DRIVER thành trình pusher:

BROADCAST_DRIVER=pusher

Trong tệp config/broadcasting.php, cập nhật giá trị hostpost như sau:

'pusher' => [
    'driver' => 'pusher',
    'key' => env('PUSHER_APP_KEY'),
    'secret' => env('PUSHER_APP_SECRET'),
    'app_id' => env('PUSHER_APP_ID'),
    'options' => [
        'cluster' => env('PUSHER_APP_CLUSTER'),
        // 'encrypted' => true,
        'host' => '127.0.0.1',
        'port' => 6001,
        'scheme' => 'http'
    ],
],

Các bạn cần chú ý 1 điều là : Nếu bạn đang sử dụng SSL cho máy chủ WebSockets, bạn sẽ cần cập nhật giá trị scheme thành https và bỏ cái comment trong options của thằng encrypted nha.

Tiếp theo trong tệp .env của bạn, hãy đặt chi tiết Pusher của bạn:

PUSHER_APP_ID=12345
PUSHER_APP_KEY=ABCDEFG
PUSHER_APP_SECRET=HIJKLMNOP
PUSHER_APP_CLUSTER=mt1

Bạn hãy đảm bảo thay đổi các giá trị thành một số giá trị an toàn. Không quan trọng bạn đặt chúng là gì, miễn là chúng an toàn.

Chạy máy chủ Laravel WebSockets

Để chạy máy chủ Laravel WebSockets, bạn cần chạy lệnh sau:

php artisan websockets:serve

Thao tác này sẽ khởi động máy chủ WebSockets trên cổng 6001.Sau đó bạn hãy truy cập vào domain/laravel-websockets trong trình duyệt của mình, bạn sẽ thấy số liệu thống kê theo thời gian thực.

Sau này lên server thật thì các bạn cài thêm thằng supervisord để tự động chạy nhé ! Tương lai mình sẽ ra bài này sau vậy..

Tạo mới một event

Tiếp theo, Để test được máy chủ WebSockets của chúng ta tớ sẽ thực hiện bằng cách tạo một sự kiện mới nhé.

Bạn có thể làm dùng cmd để tạo một event cho nhanh nè:

php artisan make:event NewMessage

Cmd trên sẽ tạo một event mới có tên NewMessage.php trong thư mục app/event.

Mở tệp NewMessage.php và copy đoạn code của mình dưới đây vào nhé:

<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class NewMessage implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $message;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct($message)
    {
        $this->message= $message;
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new Channel('messages');
    }
}

Dưới đây mình sẽ tóm tắt nhanh những thay đổi trong cái file event này nhá :

  1. Class NewMessage implement ShouldBroadcast Interface
  2. Chúng ta định nghĩa một thuộc tính public gọi là $message
  3. Trong hàm khởi tạo, chúng ta đã gán thuộc tính $message cho tham số $message
  4. Chúng ta đã thêm phương thức BroadcastOn trả về một Channel instance mới. Đối với private channel, bạn có thể sử dụng class PrivateChannel.

Ok đi test thôi nào ! Để mà test nhanh được các event thay vì phải đi tạo route sau đó thì call tới thằng event này thì các bạn có thể dụng laravel tinder luôn cho nhanh nha :

php artisan tinker

Sau đó trigger cái event bằng cách chạy như sau:

event (new \App\Events\NewMessage('Hello s2sontech'))

Tiếp theo, nếu bạn truy cập /laravel-websockets trong trình duyệt của mình, bạn sẽ thấy sự kiện ở đó , click vào connect nhé:

Cấu hình Laravel Echo

Với tất cả các bước trên, máy chủ WebSockets hiện đang chạy và backend sẵn sàng nhận các sự kiện. Bước tiếp theo là cấu hình Laravel Echo để chúng ta có thể sử dụng nó để gửi các sự kiện đó đến giao diện người dùng.

Nếu bạn chưa cài đặt npm của mình, bạn có thể cài đặt chúng bằng cách chạy lệnh sau:

npm install

nếu không có npm trên máy của bạn thì cài nodejs nhé nó đi kèm cùng nodejs.

Cài đặt dependency Laravel Echo và thư viện Pusher JS:

npm install --save-dev laravel-echo pusher-js

Sau đó, trong tệp resource/js/bootstrap.js, hãy thêm vào như sau:

import Echo from "laravel-echo"
import Pusher from "pusher-js";
window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: 'ABCDEFG', //import.meta.env.VITE_PUSHER_APP_KEY,
    wsHost: window.location.hostname,
    cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? "mt1",
    wsPort: 6001,
    forceTLS: false,
    disableStats: true,
});

// đoạn code dưới đây là để chạy test nha,
window.Echo.channel("messages").listen("NewMessage", (e) => {
    console.log(e.message);
    document.getElementById('latest_trade_user').innerText = e.message;
})

Sau đó biên dịch nội dung bằng cách chạy lệnh sau:

npm run dev

Note: Trên production thì chạy lệnh npm run production

Như vậy, chúng ta đã hoàn tất việc cấu hình Laravel Echo! Tiếp theo, hãy tiếp tục và thêm phần này vào view Blade của chúng ta để chúng ta có thể thấy nó hoạt động như thế nào nhé!

Work với Laravel Echo trên Frontend

Những gì bạn cần đưa vào view blade của mình như sau, bạn có thể sử dụng cái trang welcome.blade.php mặc định của thằng laravel mà test nhé:

<head>
 .....
 @vite('resources/js/app.js')

</head>

trong thẻ head các bạn thêm thằng @vite vào nhé ! nếu là laravel version 9 trở lên đã đc tích hợp thằng vite rồi , còn không thì các bạn làm như dưới đây :

<script src="{{ asset('js/app.js') }}"></script>
<script>
     Echo.channel('messages').listen('NewMessage', (e) => {
        console.log(e.message);
     })
</script>

Để hoạt hoạt động, hãy cập nhật file resource/views/welcome.blade.php rồi copy đoạn code của mình bên dưới đây nhé:

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Laravel EventStream</title>

        <meta name="csrf-token" content="{{ csrf_token() }}" />
        <link href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap" rel="stylesheet">
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tailwindcss/dist/tailwind.min.css">
        @vite('resources/js/app.js')

    </head>
    <body>
        <div class="container w-full mx-auto pt-20">
            <div class="w-full px-4 md:px-0 md:mt-8 mb-16 text-gray-800 leading-normal">

                <div class="flex flex-wrap">
                    <div class="w-full md:w-2/2 xl:w-3/3 p-3">
                        <div class="bg-white border rounded shadow p-2">
                            <div class="flex flex-row items-center">
                                <div class="flex-shrink pr-4">
                                    <div class="rounded p-3 bg-yellow-600"><i class="fas fa-user-plus fa-2x fa-fw fa-inverse"></i></div>
                                </div>
                                <div class="flex-1 text-right md:text-center">
                                    <h5 class="font-bold uppercase text-gray-500">Latest trade</h5>
                                    <h3 class="font-bold text-3xl">
                                        <p>
                                            Name: <span id="latest_trade_user"></span>
                                        </p>
                                    </h3>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </body>
</html>

Và kết quả như hình nè :

Vậy là xong rồi , trước khi kết thúc chắc mình làm thêm 1 cái so sánh giữa thằng websockets với thằng SSE để các bạn có thêm cái nhìn tổng quan hơn nữa nhé !

WebSockets so với SSE

Một cách khác để gửi sự kiện là sử dụng giao thức Server-Sent-Events. Có nhiều ưu và nhược điểm khi sử dụng WebSockets so với SSE và dưới đây là một số trong số đó nè:

  • WebSockets cung cấp cho bạn kết nối hai chiều theo thời gian thực
  • SSE là kết nối một chiều, nghĩa là bạn chỉ có thể gửi các sự kiện từ server đến client
  • WebSockets có hỗ trợ riêng cho hầu hết các trình duyệt web
  • SSE là một giao thức đơn giản hơn và được transported qua HTTP đơn giản và không yêu cầu giao thức tùy chỉnh
  • SSE cung cấp khả năng mở rộng quy mô dễ dàng hơn và không yêu cầu bất kỳ quy tắc tường lửa tùy chỉnh nào.

Kết luận

Ok vậy là xong rồi , bạn có thể sử dụng websockets để áp dụng cho ứng dụng của bạn , chúc các bạn thành công .

 
 
 
 
 
 

Bình luận (0)

Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough

Bài viết liên quan

Learning English Everyday