Laravel echo

Mở bài

Xin chào các bạn! Chắc hẳn khi sử dụng laravel bạn đã biết đến Broadcasting của laravel (hay có người gọi là laravel-echo). Broadcasting của laravel trong bài viết này mình sẽ dùng laravel-echo ở phía client và mình sẽ giới thiệu 2 cách để tạo server socket:

Và chắc hẳn các bạn khi cài đặt lần đầu sẽ gặp rất nhiều rắc rối đối với công cụ này. Có một hôm đẹp trời, bạn mình có hỏi tại sao khi sử dụng private channel của thằng laravel echo này toàn bị lỗi token mismatch nhỉ. Hay chỉ là cách làm sao lấy được api key của pusher.

Hôm nay, mình sẽ trả lời các câu hỏi đó. Nói có sách mách có project. Bây giờ chúng ta cùng cài một ứng dụng cụ thể dùng Broadcasting. Bạn sẽ từ từ hiểu ra câu trả lời thôi.

Mình sẽ cài bằng cả 2 cách laravel-echo-server hoặc dùng prusher, tất nhiên ứng dụng sẽ hoạt động ngon lành cành đào không gặp một lỗi nào 😃.

Thân bài

Chuẩn bị laravel project

Đầu tiên các bạn phải tạo một project laravel sau đó cấu hình database file .env và chạy:

composer install
npm install
sudo chmod 777 -R bootstrap/cache storage
php artisan key:generate
php artisan migrate
php artisan make:auth

Bạn phải cấu hình vitual host cho project laravel nhé.

Bỏ command trong file config/app.php

App\Providers\BroadcastServiceProvider::class,

Sửa file view home.blade.php

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-10 col-md-offset-1">
            <div class="panel panel-primary">
                <div class="panel-heading">Chat Box</div>
                <div class="panel-body" style="height: 350px; overflow-y: auto" id="content">
                </div>
                <div class="panel-footer">
                    <div class="input-group">
                        <input type="text" class="form-control" id="input" placeholder="Enter your message...">
                        <span class="input-group-btn">
                            <button class="btn btn-default" type="button" id="send">Send</button>
                        </span>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

Tạo sự kiện chat

php artisan make:event ChatEvent

Nội dung file ChatEvent.php

<?php

namespace App\Events;

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

class ChatEvent 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 Channel|array
     */
    public function broadcastOn()
    {
        return new PrivateChannel('chat-room');
    }
}

Lưu ý nhỏ:

  • Event phải implements ShouldBroadcast thì mới Broadcast được.
  • PrivateChannel('chat-room'); broadcast ra private channel
  • Channel('chat-room') broadcast ra public channel

Tạo route

Route::post('/comment', function (Illuminate\Http\Request $request) {
    event(new App\Events\ChatEvent($request->get('message')));
    return [
        'status' => true,
    ];
})->name('comment');

Thêm phần xác thực user trong file routes/channels.php

Broadcast::channel('chat-room', function ($user) {
    return (int) $user->id < 3;
});

Ở đây nếu user có id < 3 mới có thể chat được. Còn user có id lớn hơn hoặc bằng 3 thì không thể xác thực. Bạn hãy thử sau khi làm xong nhá.

Xong phần chuẩn bị chung cho cả 2 cách cài đặt. Bây giờ sẽ đến phần cài đặt riêng.

  • Nếu bạn dùng redis, laravel-echo-server, socket.io thì làm theo Cài đặt client - server 1
  • Còn khi dùng pusher thì làm theo Cài đặt client - server 2.

Cài đặt client - server 1

Nếu sử dụng server 1 (có redis) thì bạn phải cài redis.

Cài đặt thêm các gói cần thiết:

  • Composer
composer require predis/predis
  • Npm Thêm các gói sau vào file package.json rồi chạy npm install
"dotenv": "^2.0.0",
"laravel-echo": "^1.3.0",
"laravel-echo-server": "^1.1.0",
"redis": "^2.4.2",
"socket.io": "^1.4.5",

Config Driver Sửa file .env

BROADCAST_DRIVER=redis

Config các biến Sửa file .env

ECHO_KEY=0e1052d6edc3db2c
ECHO_HOST=laravel-echo-test.vn
ECHO_AUTH_HOST=http:\\laravel-echo-test.vn
ECHO_AUTH_ENDPOINT="/broadcasting/auth"
ECHO_DATABASE=redis
ECHO_REDIS_HOST=127.0.0.1
ECHO_SQLITE_PATH="/database/laravel-echo-server.sqlite"
ECHO_DEV_MODE=false
ECHO_PROTOCOL=http
ECHO_PORT=9090
ECHO_SSL_CERT_PATH=
ECHO_SSL_KEY_PATH=

Thay laravel-echo-test.vn thành tên host của bạn, thay ip vào là nó không chạy đúng đâu nhé. Bạn có thể đổi cổng tại ECHO_PORT=9090 Có thể đổi ECHO_KEY=0e1052d6edc3db2c. Cái này giống APP_KEY của laravel đấy nó chỉ cần là 1 chuỗi bất kì thôi.

Tạo server Tạo file server.js ở thư mục gốc với nội dung như sau:

require("dotenv").config();
var Echo = require("laravel-echo-server");

/**
 * The Laravel Echo Server options.
 */

var options = {
    "appKey": process.env.ECHO_KEY,
    "authHost": process.env.ECHO_AUTH_HOST,
    "authEndpoint": process.env.ECHO_AUTH_ENDPOINT,
    "database": process.env.ECHO_DATABASE,
    "databaseConfig": {
        "redis": {
            "port": 6379,
            "host": process.env.ECHO_REDIS_HOST
        },
        "sqlite": {
            "databasePath": process.env.ECHO_SQLITE_PATH
        }
    },
    "devMode": process.env.ECHO_DEV_MODE,
    "host": process.env.ECHO_HOST,
    "protocol": process.env.ECHO_PROTOCOL,
    "port": process.env.ECHO_PORT,
    "referrers": [],
    "socketio": {},
    "sslCertPath": process.env.ECHO_SSL_CERT_PATH,
    "sslKeyPath": process.env.ECHO_SSL_KEY_PATH,
    "verifyAuthPath": true,
    "verifyAuthServer": true
};

/**
 * Run the Laravel Echo Server.
 */
Echo.run(options);

Sửa các file script Sửa file aserts/js/bootstrap.js

window.$ = window.jQuery = require('jquery');
require('bootstrap-sass');
let token = document.head.querySelector('meta[name="csrf-token"]');
$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': token.content
    }
});

import Echo from 'laravel-echo';

window.io = require('socket.io-client');
window.Echo = new Echo({
    namespace: 'App.Events',
    broadcaster: 'socket.io',
    host: `${window.location.hostname}:9090`
});

Mình giải thích một chút:

  • namespace: 'App.Events' : Event của bạn để ở trong thư mục app\Events và có namespace là App\Events. Khi event được kích hoạt thì nó sẽ Broadcast với tên event đầy đủ có cả namespace. Mình cho namespace vào đây thì lúc lắng nghe sự kiện chỉ cần lắng nghe với tên class thôi.
  • host: ${window.location.hostname}:9090 : Cái này nó sẽ lấy tên host của web kiểu như: laravel-echo-test.vn:9090. Lúc đầu mình bảo phải tạo vitual host cho project của mình rồi đấy. Bạn không thay Ip vào được đâu. Nó sẽ bị lỗi token mismatch ngay.
  • lưu ý nữa là window.io = require('socket.io-client'); chữ io phải viết thường nếu bạn lỡ tay viết thành Io thì nó cũng sẽ lỗi

Sửa file aserts/js/app.js

require('./bootstrap');

$('#send').on('click', function () {
    let message = $('#input').val();
    $('#input').val('');
    if (message != '') {
        $.ajax({
            url: 'comment',
            type: 'POST',
            dataType: 'json',
            data: {message: message},
        });
    }
});

Echo.private('chat-room')
    .listen('ChatEvent', (e) => {
        console.log(e);
        $('#content').append(`<div class="well">${e.message}</div>`);
    });

Ở phần này thì mình sẽ không giải thích nhiều vì nó quá dễ hiểu rồi. Bạn chỉ cần lưu ý thế này thôi:

  • Echo.private là để lắng nghe private channel
  • Echo.channel để lắng nghe public channel
  • .listen('ChatEvent', calback) lắng nghe event. Nếu phần khởi tạo Echo mà không có namespace thì ở đây phải cho tên đầy đủ của event class (Bao gồm cả namespace).

Cuối cùng là bật server lên

node server.js

Thế là đã xong. Hãy vào trang web của mình đã tạo để cảm nhận. Hãy nhớ chạy npm run dev hoặc npm run watch nhé.

Cài đặt client - server 2

Cài đặt server 1 thật vất vả phải không nào.

Bây giờ chúng ta sẽ cùng cài đặt server 2 dùng pusher. Cái này thì sẽ dùng dịch vụ của thằng khác nên nó sẽ chạy chậm hơn là laravel-echo-server đặt tại server của mình. Đầu tiên phải vào trang chủ của pusher để đăng kí một tài khoản https://pusher.com. Bạn có thể login bằng github hay google cũng được. Miễn sao có một tài khoản pusher để sử dụng.

Dashboard của pusher có dạng thế này:

Vào your app tạo 1 app mới

Đặt tên cho app, chọn cluster ==> Create my app

Vào app đã tạo để lấy key, app_id, secret, cluster. Bạn chỉ cần bấm vào app là nó sẽ hiện ra luôn trong tab overview rồi. Bạn có thể bấm vào tab App Key để dễ nhìn hơn:

Cài các gói cần thiết:

  • Composer
"pusher/pusher-php-server": "^2.6"
  • Npm
"laravel-echo": "^1.3.0",
"pusher-js": "^3.2.4",

Điền các biến tương ứng đó vào file .env

PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_CLUSTER=

Cấu hình cluster trong file config/broadcasting.php

'pusher' => [
    'driver' => 'pusher',
    'key' => env('PUSHER_APP_KEY'),
    'secret' => env('PUSHER_APP_SECRET'),
    'app_id' => env('PUSHER_APP_ID'),
    'options' => [
        'cluster' => env('PUSHER_CLUSTER'),
        'encrypted' => true
    ],
],

Sửa file assert/js/bootstrap.js

window.$ = window.jQuery = require('jquery');

require('bootstrap-sass');
let token = document.head.querySelector('meta[name="csrf-token"]');
$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': token.content
    }
});

import Echo from 'laravel-echo'

window.Pusher = require('pusher-js');

window.Echo = new Echo({
    namespace: 'App.Events',
    broadcaster: 'pusher',
    key: '11f716410294b4f3***',
    cluster: 'ap1',
    encrypted: true
});

Thay keycluster bên trên bằng keycluster của bạn

File aserts/js/app.js giống với file của server 1

require('./bootstrap');

$('#send').on('click', function () {
    let message = $('#input').val();
    $('#input').val('');
    if (message != '') {
        $.ajax({
            url: 'comment',
            type: 'POST',
            dataType: 'json',
            data: {message: message},
        });
    }
});

Echo.private('chat-room')
    .listen('ChatEvent', (e) => {
        $('#content').append(`<div class="well">${e.message}</div>`);
    });

Xong rồi bạn chạy npm run dev hoặc npm run watch và vào trang của mình để hưởng thụ thành quả.

Cấu hình pusher thật đơn giản phải không

Kết luận

Qua bài viết này mình đã cùng với các bạn cài đặt và sử dụng thành công broadcast của laravel. Hi vọng sẽ giúp ích được cho các bạn.

Nếu có bất cứ câu hỏi hay khó khăn gì hãy comment bên dưới.

Nếu thấy bài viết hay thì hãy upvote và chia sẻ cho mọi người nhé.


All Rights Reserved