+19

Viết ứng dụng chat trong Laravel sử dụng Private và Presence channel

Cập nhật gần nhất: 25/11/2024

Chào mừng các bạn quay trở lại với series viết ứng dụng chat realtime sử dụng Laravel, VueJS, Laravel Echo của mình. 👋👋

Ở bài trước mình đã hướng dẫn các bạn viết ứng dụng chát đơn giản, dùng public channel trong Laravel, nhược điểm của public channel là khi 1 user gửi tin nhắn thì toàn bộ tất cả các user khác đều có thể nhận được. Thực tế thì ta sẽ thường muốn 1 user gửi tin nhắn đến chỉ 1 hoặc 1 số user khác.

Và để làm điều đó thì bìa hôm nay mình sẽ hướng dẫn các bạn sử dụng privatepresence channel trong laravel để xác thực user và gửi tin nhắn đến 1 số user nhất định, thay vì toàn bộ như trước kia.

Ở bài này ta sẽ xây dựng:

  • Một chatroom có 2 phòng, user có thể gửi tin nhắn khi ở trong phòng
  • User ở phòng nào sẽ chỉ nhận được tin nhắn ở phòng đó (phần private channel)
  • Tiếp đó ta sẽ hiển thị thông tin chi tiết từng user có trong phòng (phần presence channel)

Và có 1 điều đặc biệt là ở bài này ta sẽ dùng Laravel Reverb mới toanh từ Laravel nha:

Screenshot 2024-11-24 at 5.48.58 PM.jpg

Chuẩn bị

Điều kiện tiên quyết

Nghe tiên quyết như học sinh cấp 3 🤣🤣

Các bạn cần phải cài đặt redis. Gõ command redis-cli để check nhé. Nếu thấy báo lỗi không có thì search google cách cài với từng nền tảng Win, Mac, Linux nhé.

Tiếp đó là các bạn cũng cần phải có MySQL cài sẵn đó nhé

Và cuối cùng không thể thiếu đó là PHP >= 8.2

Rất nhiều bạn thiếu bước này đó. Lời khuyên của mình là các bạn dùng Docker để chạy Redis + MySQL cho lành nha 😘

Thiết lập project

Ở bài này để tiết kiệm thời gian, mình đã tạo sẵn một project mẫu cho các bạn rồi nhé.

Các bạn clone source code ở đây: https://github.com/maitrungduc1410/viblo-private-chat-app

Sau khi clone các bạn chạy lần lượt command sau để setup project:

composer install
npm install
cp .env.example .env
php artisan key:generate

Sau đó các bạn setup lại thông số database ở file .env cho phù hợp với máy của các bạn nha, ví dụ bên dưới của mình nom như sau:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=chat_app
DB_USERNAME=root
DB_PASSWORD=

Ta có thể tạo sẵn database chat_app (hoặc không thì tí nữa đoạn migrate Laravel làm thay cũng được) 😁

Oke thì ta migrate và seed dữ liệu nhé:

php artisan migrate --seed

Screenshot 2024-11-24 at 10.41.07 PM.jpg

Cuối cùng chạy app để test thử coi xem sao nhen, các bạn chạy các command sau:

php artisan serve
npm run dev

Sau đó ta mở trình duyệt ở địa chỉ http://localhost:8000/, tiến hành tạo tài khoản login, zô gửi vào tin nhắn các kiểu đảm bảo mọi thứ okela nha 😎:

Screenshot 2024-11-24 at 10.42.41 PM.jpg

Screenshot 2024-11-24 at 10.42.53 PM.jpg

Screenshot 2024-11-24 at 10.43.00 PM.jpg

Tổng quan project

Mình sẽ giải thích một lượt về project để các bạn nếu muốn chỉnh sửa có thể làm dễ dàng nhé.

Các mục cần quan tâm:

  • File routes/web.php ở đây mình định nghĩa vài routes đơn giản. Ở cuối cùng của file này mình có bắt route::any nhằm fix lỗi của Vue-router trả về 404 nếu các bạn để mode: 'history' nhé.
  • Mình chỉ có 2 model là User và Message. Mỗi message có room_id (message được gửi ở phòng nào, khoá ngoại tới bảng chatrooms), user_id (ai là người gửi, khoá ngoại tới bảng users) và content (nội dung tin nhắn)
  • Có 2 controller là MessageController (hiển thị và lưu message) và AppController (trả về view chứa frontend kèm theo data). Mục đích trả kèm theo data là mình muốn các thông tin như user, chatroom được trả về ngay khi user login thành công, trước khi gọi vào VueJS, để lát nữa mình không phải tốn request gọi lại nữa, vì đây là 2 thành phần không đổi trong suốt quá trình sử dụng.
  • File resources/views/app.blade.php là file trả về frontend VueJS. các bạn có thể thấy mình có biến window.__app__ = @json($data), đây là data được trả về kèm với view (xem AppController). biến __app__ này lát nữa sẽ được dùng ở file app.js của VueJS nhé 😁

Nói chung project ở bước này khá đơn giản, chỉ là dạng CRUD, chưa có realtime. Các bạn có thể chọn 1 chatroom, nhập 1 dòng tin nhắn và bấm gửi, mở tab trình duyệt khác sẽ không thấy realtime mà phải load lại trình duyệt.

Bắt đầu vào phần realtime thôi nào 🚀🚀

Realtime với Private Channel

Âu cây, hiện tại ở Laravel 11 thì phần Broadcasting đã không được cài sẵn mà ta phải tự cài nó với command sau:

php artisan install:broadcasting

Khi được hỏi có cài Reverb + Node dependencies không thì ta chọn Yes nhé:

Screenshot 2024-11-24 at 5.03.26 PM.jpg

Screenshot 2024-11-24 at 5.03.45 PM.jpg

Khi cài Oke thì ở .env ta phải thấy xêm xêm như sau:

Screenshot 2024-11-24 at 5.05.45 PM.jpg

Chú ý: BROADCAST_CONNECTION=reverb nhé

Tiếp theo ta cài thêm 2 packages sau cho Frontend nhé:

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

Lý do ở trên ta cài pusher-js là vì Reverb nó cũng follow theo protocol của Pusher

Tiếp theo ta mở file resources/js/bootstrap.js, kéo xuống dưới cùng sẽ thấy là ở đoạn install broadcasting vừa nãy nó đã tự động thêm:

import './echo';

Và file echo.js có nội dung như sau cũng đã được tạo ra:

import Echo from 'laravel-echo';

import Pusher from 'pusher-js';
window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'reverb',
    key: import.meta.env.VITE_REVERB_APP_KEY,
    wsHost: import.meta.env.VITE_REVERB_HOST,
    wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
    wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
    forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
    enabledTransports: ['ws', 'wss'],
});

Oke ngon rồi, với Laravel Reverb thì Laravel làm hết cho ta luôn, nãy giờ ta chả phải setup mấy 😂 (khác hẳn so với việc dùng laravel-echo-server)

Ý tưởng làm realtime ở bài này như sau: khi 1 user join vào 1 chatroom, gửi đi 1 tin nhắn, khi tin nhắn được lưu thành công sẽ thông báo (broadcast) với các user chỉ ở trong chatroom đó, ta dùng Event trong Laravel để broadcast nhé.

Ta tạo event MessagePosted (event này sẽ được gọi mỗi khi có tin nhắn được lưu thành công):

php artisan make:event MessagePosted

Sau đó ta mở file app/Events/MessagePosted và sửa lại như sau:

<?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;

use App\Models\Message;

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

    public $message;

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

    /**
     * Get the channels the event should broadcast on.
     *
     * @return array<int, \Illuminate\Broadcasting\Channel>
     */
    public function broadcastOn()
    {
        return new PrivateChannel('room.'.$this->message->room_id);
    }
}

Chú ý đoạn implements ShouldBroadcastuse App\Models\Message; nha 😉

Giải thích chút nhé: ở event này ta nhận vào 1 tham số là message vừa được lưu, sau đó broadcast cho các users khác qua Private channel với tên channel là room của message.

Tiếp theo, vì là bây giờ ta dùng Private Channel, nên ta phải login trước thì lát nữa mới có thể lắng nghe sự kiện nhé. Đồng thời, khi login xong user có tuỳ quyền chọn vào 1 trong các chatroom định sẵn do đó ở file routes/channels.php ta thêm vào như sau nhé:

<?php

use Illuminate\Support\Facades\Broadcast;

Broadcast::channel('room.{id}', function ($user, $id) {
    return true; // user có thể join vào bất kì chatroom nào
});

Chú ý rằng ở callback ta có $user là user sau khi đã authenticated, tức là đã đảm bảo rằng họ đã login

Setup phần broadcast ổn rồi đó. Giờ ta quay lại file MessageController.php ở hàm store (để lưu tin nhắn) ta sửa lại như sau:

use App\Events\MessagePosted; // thêm dòng này ở đầu

...

public function store (Request $request) {
    $message = new Message();
    $message->room_id = $request->input('room_id', -1);
    $message->user_id = Auth::user()->id;
    $message->content = $request->input('content', '');

    $message->save();

    // Thêm dòng bên dưới
    // Gửi đến các user khác trong phòng TRỪ user tạo tin nhắn này
    broadcast(new MessagePosted($message->load('user')))->toOthers();

    return response()->json(['message' => $message->load('user')]);
}

Ổn rồi đó, giờ ta qua frontend để lắng nghe sự kiện bắt tin nhắn mới nhé 😘

Các bạn mở file resources/js/pages/Room.vueonBeforeMount các bạn sửa lại như sau:

onBeforeMount(() => {
  getMessages()
  const index = rootData.rooms.findIndex(item => item.id === parseInt(route.params.roomId))
  if (index > -1) {
    currentRoom.value = rootData.rooms[index]

    Echo.private(`room.${currentRoom.value.id}`)
      .listen('MessagePosted', (e) => {
        messages.value.push(e.message)

        scrollToBottom()
      })
  }
})

Giải thích chút nhé:

  • onBeforeMount đầu tiên ta lấy danh sách tin nhắn ứng với room ID hiện tại, room ID được trichs từ URL hiên tại (dùng route.params.roomId)
  • vẫn ở onBeforeMount ta check xem room ID có tồn tại trong danh sách room hay không (đề phòng user tự sửa room id và cho load lại trang)
  • nếu có thì ta mới tiến hành lắng nghe tin nhắn dùng Echo.private, khi có tin nhắn mới thì ta đẩy vào mảng danh sách message

Tiêp theo đó vẫn ở Room.vue ta thêm vào:

import { onBeforeMount, ref, getCurrentInstance, nextTick, onBeforeUnmount } from 'vue'

//...

onBeforeUnmount(() => {
  // huỷ lắng nghe tin nhắn ở chatroom hiện tại
  // nếu như user chuyển qua route/chatroom khác
  Echo.leaveChannel(`room.${currentRoom.value.id}`)
})

Ô kê đến giờ test rồi. Các bạn tắt hết các cửa sổ terminal đang chạy, clear config bằng command php artisan config:clear và ta tiến hành khởi động lại bằng các command sau nhé, mỗi command chạy ở 1 terminal nhé:

php artisan serve
npm run dev
php artisan reverb:start --debug
php artisan queue:work

ta chạy Reverb với option --debug để xem đầy đủ log ở terminal nha

Âu cây ròi, giờ ta mở trình duyệt, 2 tab, 1 tab thường 1 tab ẩn danh, login với 2 account, vô cùng 1 phòng và chat với nhau rồi xem thành quả nhen 😘.

ezgif-4-d7f159e0d1.gif

Note: mỗi khi gửi tin nhắn thì các bạn check lại 2 terminal chạy Reverb và queue:work hiển thị như sau là oke nhé:

Screenshot 2024-11-25 at 9.05.50 PM.jpg

Screenshot 2024-11-25 at 9.07.12 PM.jpg

Tiếp theo các bạn thử cho mỗi user join vào 1 phòng và lại thử nhắn tin tiếp, ta để ý là user ở phòng nào thì chỉ nhận được tin nhắn realtime từ phòng đó. Tuyệt vời 😘

Giờ vấn đề tiếp theo là làm cách nào để lấy được thông tin chi tiết từng user trong phòng và hiển thị. Cùng đi tiếp tới phần sau nhé các bạn

Buggg

Ầu... có gì lạ lạ à nha.

Đúng là từ A gửi tin nhắn sang B thì phía B realtime rồi, cơ mà phía A cũng nhận được tin nhắn, dẫn đến tình trạng tin nhắn bị lặp.

Ê mà ở phía Laravel ta có boadcast()->toOthers rồi mà ta 🤔🤔🤔

Đọc lại documentation của Laravel tí coi nha: https://laravel.com/docs/master/broadcasting#only-to-others-configuration

Àaaaaaaa...thì ra là ta phải gửi cả socketId theo request (axios) lên cho Laravel nữa, thì khi broadcast nó mới bỏ qua socketId của người gửi (sender)

Tức là ở file Room.vue -> saveMessage(), đoạn axios.post ta phải sửa như sau:

const saveMessage = async (content) => {
  try {
    const response = await axios.post('/messages', {
      room_id: parseInt(route.params.roomId),
      content
    }, {
      headers: {
        'X-Socket-ID': window.Echo.socketId(),
      }
    })
    messages.value.push(response.data.message)
    scrollToBottom()
  } catch (error) {
    console.log(error)
  }
}

Ta lưu lại và quay lại trình duyệt F5 là sẽ thấy oke nha, không còn hiện tượng bị lặp tin nhắn 👍️👍️

Ta thử gửi 1 message và inspect API kiểm tra header xem nha:

Screenshot 2024-11-28 at 1.07.08 PM.jpg

Presence Channel

Giờ để hiển thị danh sách user đang có trong phòng thì ta sẽ dùng Presence Channel nhé

Presence channel cũng chính là Private channel nhưng ở đó ta lấy được thông tin cụ thể từng user

Ở file routes/channels.php, ta sửa lại như sau nhé:

Broadcast::channel('room.{id}', function ($user, $id) {
    // // giờ đây ta trả về thông tin user chứ không trả về true/false nữa
    return $user;
});

Tiếp theo ta quay lại file app/Events/MessagePosted.php và sửa lại hàm broadcastOn như sau:

public function broadcastOn()
{
    return new PresenceChannel('room.'.$this->message->room_id);
}

Sau đó ta quay lại file Room.vuecreated ta sửa lại như sau:

onBeforeMount(() => {
  getMessages()
  const index = rootData.rooms.findIndex(item => item.id === parseInt(route.params.roomId))
  if (index > -1) {
    currentRoom.value = rootData.rooms[index]

    Echo.join(`room.${currentRoom.value.id}`)
      .here((users) => { // gọi ngay thời điểm ta join vào phòng, trả về tổng số user hiện tại có trong phòng (cả ta)
        usersOnline.value = users
      })
      .joining((user) => { // gọi khi có user mới join vào phòng
        usersOnline.value.push(user)
      })
      .leaving((user) => { // gọi khi có user rời phòng
        const index = usersOnline.value.findIndex(item => item.id === user.id)
        if (index > -1) {
          usersOnline.value.splice(index, 1)
        }
      })
      .listen('MessagePosted', (e) => {
        messages.value.push(e.message)

        scrollToBottom()
      })
  }
})

Giờ ta đóng tất cả terminal đi và start mới:

php artisan serve

npm run dev

php artisan reverb:start --debug

php artisan queue:work

Ngay sau đó các bạn load lại trang, và BÙM, ta có kết quả như sau:

Screenshot 2024-11-25 at 9.35.47 PM.jpg

Lấy thông tin user dùng Presence Channel

Presence channel cũng chính là Private channel nhưng ở đó ta lấy được thông tin cụ thể từng user

Thế có bạn sẽ hỏi: thế vậy tôi cần cái Private channel làm gì, dùng luôn Presence channel đi, thông tin user sau này cần thì dùng không thì thôi 😘

Đúng mình cũng có câu hỏi như vậy và hiện tại chưa tìm được 1 câu trả lời chính thống cụ thể nào. Nhưng mình đã sớm nhận ra là Presence channel khi broadcast sẽ chậm hơn Private channel 1 chút, cái "1 chút" này đủ dài để ta có thể cảm nhận được 😁

Thôi tiếp tục phần này nào 🚀🚀.

Ở file routes/channels.php, ta sửa lại như sau nhé:

Broadcast::channel('room.{id}', function ($user, $id) {
    // // giờ đây ta trả về thông tin user chứ không trả về true/false nữa
    return $user;
});

Tiếp theo ta quay lại file app/Events/MessagePosted.php và sửa lại hàm broadcastOn như sau:

public function broadcastOn()
{
    return new PresenceChannel('room.'.$this->message->room_id);
}

Sau đó ta quay lại file Room.vuecreated ta sửa lại như sau:

onBeforeMount(() => {
  getMessages()
  const index = rootData.rooms.findIndex(item => item.id === parseInt(route.params.roomId))
  if (index > -1) {
    currentRoom.value = rootData.rooms[index]

    Echo.join(`room.${currentRoom.value.id}`)
      .here((users) => { // gọi ngay thời điểm ta join vào phòng, trả về tổng số user hiện tại có trong phòng (cả ta)
        usersOnline.value = users
      })
      .joining((user) => { // gọi khi có user mới join vào phòng
        usersOnline.value.push(user)
      })
      .leaving((user) => { // gọi khi có user rời phòng
        const index = usersOnline.value.findIndex(item => item.id === user.id)
        if (index > -1) {
          usersOnline.value.splice(index, 1)
        }
      })
      .listen('MessagePosted', (e) => {
        messages.value.push(e.message)

        scrollToBottom()
      })
  }
})

Ngay sau đó các bạn load lại trang, và BÙM, ta có kết quả như sau:

Screenshot 2024-11-25 at 9.35.47 PM.jpg

Bài tập về nhà

Nghe bài tập về nhà lại giống cấp 3 🤣🤣

Giờ đây ta có thông tin của toàn bộ user trong phòng rồi. Các bạn thử tự mình làm thêm 1 chức năng nhắn tin riêng 1-1 với 1 user nào đó trong phòng. Ví dụ: bấm click chọn một user trong danh sách user thì xuất hiện của sổ chat riêng với user đó (giống Facebook chẳng hạn), dùng Private hoặc Presence Channel chẳng hạn, nhưng theo mình chat 2 người dùng Private channel là đủ, nhanh hơn Presence channel.

Đồng thời ta thêm các sự kiện nhỏ nhỏ kiểu: "user này đang gõ", "đã xem lúc mấy giờ", báo tin nhắn đến. Để làm được những điều này các bạn cần đọc thêm chút phần sự kiện whisper ở trang chủ Laravel đây nhé

Demo

Các bạn có thể xem demo của mình ở đây nhé

Nếu bạn gặp lỗi

Trong khi code nếu có khi nào bạn gặp lỗi thì xem lại bài đầu tiên trong series này của mình phần debug mình đã ghi rấttttttt là tâm huyết rồi các bạn à 😘😘😘

Kết bài

Qua bài này hi vọng các bạn đã hiểu hơn được cách sử dụng Private và Presence Channel trong laravel để xử lý realtime data. Thường ở các dự án thật thì mình dùng 2 loại channel này chứ không dùng Public channel như bài trước , nhưng vì public channel khá dễ cấu hình, không cần xác thực nên mình giới thiệu với các bạn trước để các bạn làm quen với cách làm realtime trong Laravel.

Có rất nhiều bạn đã hỏi mình về các sử dụng Private/Presence channel, và các lỗi mà các bạn gặp phải, mong rằng qua bài này các bạn hiểu thêm về cách sử dụng chúng 😘

Trong bài nếu có gì thắc mắc các bạn cứ để lại commen cho mình nhé. Hẹn gặp các bạn ở các bài sau 👋👋


All rights reserved

Bình luận

Đăng nhập để bình luận
Avatar
@phat21
thg 7 30, 2018 1:07 CH

Hello bạn. Mình có làm giống bài viết của bạn nhưng không get được ID(this.$route.params.id) trong function created() => mình không get được chatroom_id, nhờ bạn support giúp với. Thanks!

Avatar

bạn kiểm tra lại file route.js xem đúng như mình làm ở phần đầu bài viết chưa nhé. Check kĩ phần path: '/chatroom/:id' xem nhé

Avatar
@phat21
thg 7 30, 2018 1:45 CH

Hi bạn, mình get được params từ router nhưng nó chỉ nhận ở function watch, chứ không bind vào trong function created được. bạn qua fb mình nhờ tí được không ạ. thanks: https://www.facebook.com/tvxqmessi

Avatar
@thuyettiensinh
thg 10 1, 2018 3:50 CH

[ioredis] Unhandled error event: Error: connect ECONNREFUSED 127.0.0.1:6379 at Object._errnoException (util.js:1031:13) at _exceptionWithHostPort (util.js:1052:20) at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1195:14)

Lỗi này có phải do mình thiếu redis ?

Xem thêm (8)
Avatar
@thuyettiensinh
thg 10 2, 2018 5:47 SA

Redis-x64-3.2.100.zip: https://github.com/MicrosoftArchive/redis/releases Mình phải tải thằng redis server này chạy file .exe của nó thì mới laravel-echo-server mới nhận. Có thể do máy bạn cài redis chạy background trước đó rồi nên bạn không thấy vấn đề gì. Bạn có thể test trên máy khác, nếu bị lỗi giống mình thì có thể thiếu bước cài redis-server @@

Avatar

ca này bạn cần kiểm tra lại đã cài redis chưa nhé, trên linux thì đơn giản nhưng win hay gặp lỗi lúc cài lắm 😄

Avatar
@vunguyen_1995
thg 2 28, 2019 10:25 SA

Screenshot from 2019-02-28 17-25-26.pngScreenshot from 2019-02-28 17-25-03.png

Avatar
Avatar
@vunguyen_1995
thg 2 28, 2019 10:26 SA

Bạn xem hộ mình lý do là gì vs. Thank

Avatar

bạn ơi, ở file laravel-echo-server.json, bạn check xem trường authHost đúng host và port đang chạy Laravel ko? Bình thường là thế này (local): "authHost": "http://localhost:8000",

Avatar
@moceb93
thg 6 6, 2019 7:13 SA
Xem thêm (3)
Avatar
@moceb93
thg 6 7, 2019 2:28 SA
Avatar

hiện tại mình bận việc riêng nên ko có thời gian teamview cho bạn được. Bạn check lại giúp mình:

  • Đã chạy php artisan queue:work chưa.
  • Nếu bạn đang dùng windows và làm theo các bước trên ko được thì 96,69% là redis của bạn có vấn đề. Bạn cần check lại xem đã cài redis trên windows chưa, check xem redis có listen ở port 6379 hay ko. thử chạy redis-cli xem có được hay chưa.
Avatar
@LamNguyenDev
thg 11 8, 2019 3:34 SA

Thank you very much about post. Nhưng mình làm tới install các package 'npm install --save laravel-echo laravel-echo-server socket.io-client'. Xong rồi chạy cmd 'laravel-echo-server init'. Thì báo error: laravel-echo-server: command foud. Please help me

Xem thêm (2)
Avatar
@LamNguyenDev
thg 11 11, 2019 4:24 SA

Capture.PNG

Mình đang vướng chỗ này, mặc dù đã đổi authHost và chạy php artisan queue:work

Avatar
@maitrungduc1410
thg 11 11, 2019 5:48 SA

mình có thấy lỗi j đâu nhỉ?

Avatar
@LongDinhh
thg 1 17, 2020 2:40 SA

Chào bạn, mình đang muốn làm phần chat cho App Mobile thì không biết kết nối như thế nào! Mình cảm ơn!

Xem thêm (4)
Avatar
@LongDinhh
thg 1 17, 2020 4:14 SA

Untitled.png Mình bị lỗi này! Mình có sử dụng docker nginx, và không sử dụng php artisan serve mình có public Annotation 2020-01-17 111419.png

Avatar

Bạn xem bài Dockerize ứng dụng chat với Laravel của mình nhé, khả năng cao là bạn đang chạy laravel-echo-server ở 1 container khác và cấu hình nginx chưa đúng nên không thể kết nối tới laravel echo server được.

Avatar

Screenshot from 2020-02-08 14-55-19.png Bạn ơi, mình hỏi vấn đề này 1 chút với ạ. MÌnh run dự án và chat realtime được rồi, nhưng cái lỗi như hình bên trên mình gửi là do bị gì vậy bạn ?

Avatar

trông có vẻ sai sai 😃),kia là lỗi gọi axios để lấy danh sách user trong channel, và phần đó không có trong bài này, hình như bạn đang comment nhầm sang bài đầu tiên trong series này.

Avatar

à.. mình comment nhầm, để mình change comment qua bài kia 😃)

Avatar

😉

Avatar

Em hông hiểu 2 dòng này là gì a ơi, giải thích giúp em với composer install cp .env.example .env

Xem thêm (10)
Avatar

ồ được rồi a ạ 😂

Avatar
Avatar
@danghungchannel
thg 4 1, 2020 3:04 SA

Xin chào admin, Em đã làm theo và chạy được app chat rùi ạ! Xin phép admin cho e up lên host của e để lưu ạ Nhưng khi em tải lên host để làm demo web thì bị lỗi 500 ạ. Mong được ad giúp vs ạ! Có phải do không được connect predis ạ?Captur1e.PNGCapture.PNG

Xem thêm (10)
Avatar

vấn đề là cái icanmax:6001 hiện tại đang ko truuy cập được, e phải check lại tại sao cái domain đó lại ko truy cập đc nhé, khả năng rất cao do cấu hình domain sai, còn a ko thấy có lỗi j ở bên laravel hay laravel êcho hết

Nếu e đang dùng virtual host, thì e bỏ virtual host đi test ở localhost trước đã, rất nhiều bạn học hay dùng virtual host ở localhost xong bị rất nhiều lỗi linh tinh

Avatar

oke nhắn qua messenger cho a: https://www.facebook.com/maitrungduc1410/

Avatar
@SonNguyen98
thg 4 28, 2020 2:29 SA

anh ơi.. anh làm hiệu ứng chuyển trang bằng gì thế ? nhìn mượt quá.. 😘

Avatar

transition của Vue thôi e , đây nhé

Avatar
@SonNguyen98
thg 4 28, 2020 12:47 CH

vâng cám ơn a

Avatar
@SonNguyen98
thg 4 28, 2020 12:58 CH

ui đẹp quá anh ơi...

Avatar
Avatar

a ơi bài cách e up lên host với ạ

Avatar

oke e chắc a sẽ viết 1 bài về điều này, vì có khá là nhiều bạn gặp nhiều vấn đề khi đưa lên host/vps

Avatar
@locdh41
thg 6 22, 2020 6:53 SA

hello bác, bài viết thật sự là quá hay và chu đáo. hy vọng bác sẽ ra thêm series hay như thế này. Cám ơn bác

Avatar

cảm ơn bạn dã theo dõi nhé 😄

Avatar
@john
thg 7 7, 2020 11:07 SA

Hello b minh ko start duoc service b xem giup minh loi nay bi sao nhi Untitled.png Untitled2.png

Avatar

hiện tại hình như bạn đang dùng Docker thông qua 1 phần mềm nào đó, và như mình thấy lỗi trên hình thì laravel-echo-server đang không kết nối được tới redis (ERRCONNREFUSED)

Bạn nên check lại tool bạn dùng ở phần cấu hình thông số cho đúng nhé

Avatar
@hcthang
thg 7 25, 2020 11:15 SA

error.png mình bị lỗi này nên không Echo được. Giúp mình với

Xem thêm (10)
Avatar
@maitrungduc1410
thg 7 30, 2020 10:20 SA

Ngay comment ở broadcastOn đã giải thích cho bạn rồi nhé, bạn có thể truyền vào 1 mảng (ví dụ để broadcast tới nhiều chatroom) hoặc đơn giản là 1 string (chỉ muốn broadcast tới 1 phòng)

Screenshot 2020-07-30 at 18.18.54.png

Avatar
@hcthang
thg 7 31, 2020 3:06 SA

Cảm ơn bạn. Mình sẽ chú ý hơn

Avatar
@hcthang
thg 8 1, 2020 12:43 SA

Bạn có thể thêm cập nhật cho Laravel 7x được ko bạn! Ở Laravel 6 mình làm theo bạn chạy ngon rồi nhưng apply vào project hiện tại (Laravel 7) bị lỗi quá chưa khắc phục được ạ. Chạy public channel thì vẫn ổn không sao, còn chạy PresenceChannel thì mình bị kẹt 1 số chỗ:

  • Khi run thì ở laravel-echo-server thông báo có tên channel là : laravel_database_presence-tên_channel. Ở client khi nghe với tên channel có "presence" thì lại báo lỗi không xác thực được. Bỏ đi thì hết lỗi nhưng ko đúng tên kênh nên ko nghe được.
  • Echo ở client dùng đc mỗi hàm listen. Các hàm còn lại như join, joining, leave, leaving, here là lại báo lỗi. Không được ngon nghẻ như bài này.

error-channel.png error-channel2.png

Xem thêm (5)
Avatar

Lỗi này là do object $user trả về cho Laravel echo server lại không có ở trong database.

  • Bạn check lại đã sửa BROADCAST_DRIVER=redis ở file .env hay chưa?
  • Toàn bộ những bước setup với redis ở phần "Realtime với Private Channel" bạn đã làm đủ theo mình chưa
  • Source code mình để ở branch starter-tutorial là laravel 7x rồi đó bạn.
  • Tắt hết terminal đi và chạy lại nhé, chỉ chạy duy nhất 1 project laravel 7x nhé, bạn đừng chạy đồng thời cả cái laravel 6 nữa
Avatar
@hcthang
thg 8 3, 2020 10:22 SA
Avatar
@hcthang
thg 10 2, 2020 7:10 SA

Cho mình hỏi tại sao khi dùng PresenceChannel nó lại có thể trả cho mình danh sách users ở hàm here của Echo? Lúc mới vào trang là nó đã nghe được có những user nào trong đó rồi. Vậy nếu mình muốn nhận dữ liệu khác ở hàm here đó thì sao hả bạn ơi. Cảm ơn bạn

Avatar

Cho mình hỏi tại sao khi dùng PresenceChannel nó lại có thể trả cho mình danh sách users

Câu hỏi hại não 😄, người ta làm nó ra để mục đích như vậy đó bạn

Bạn đọc lại docs phần Presence Channel nhé, here sẽ được gọi ngay lập tức khi user join vào channel thành công. Bạn muốn cho thêm cái gì khác vào đó thì tuỳ bạn, chỉ cần luôn nhớ là nó chỉ chạy khi user join vào channel là được

Avatar
@hcthang
thg 10 2, 2020 7:37 SA

Cảm ơn bạn. Do mình ko hiểu nó query chỗ nào mà lấy được dữ liệu của user. Chắc cũng giống như Auth::user(), trong hệ thống của laravel

Avatar

@hcthang khả năng là vậy đó bạn, behind the scene Laravel làm cách nào để trả về user thì ta phải vọc source code của Laravel mới biết bạn ạ 😄

Avatar
@hcthang
thg 10 16, 2020 1:28 SA

Mình đưa app lên host, trang mình có bảo mật nên chỗ init laravel-echo-server mình chọn https. Sau đó nó đòi mã path ssl mà chẳng biết ở chỗ nào 😓

Xem thêm (3)
Avatar
@hcthang
thg 10 19, 2020 7:26 SA

@maitrungduc1410 ok cảm ơn bạn nhiều

Avatar
@maitrungduc1410
thg 10 19, 2020 7:28 SA
Avatar
@spaussio
thg 11 13, 2020 9:57 SA

mình mở 2 trình duyệt thì 1 bên k báo lỗi. 1 bên thì báo lỗi như ảnh? Mong được bạn giúp đỡ. Mình cám ơn!Capture.PNG

Avatar
@maitrungduc1410
thg 11 13, 2020 1:27 CH

như lỗi in ra là không thể kết nối tới laravel echo server, có vẻ như laravel echo server đang bị down:

  • Tên domain kia của bạn là domain xịn trên server chứ ko phải virtual host bạn tạo ở local đúng ko?
  • Log ở bên laravel echo server của bạn in ra là gì tại thời điểm xảy ra lỗi?
Avatar
@spaussio
thg 11 14, 2020 1:12 SA

@maitrungduc1410 không bạn ạ. domain hiện tại trên local thôi ạ. mình mở 2 trình duyệt. 1 trình duyệt thì không có console lỗi. còn 1 bên thì như ảnh mình gửi phía trên ạ

Avatar
@maitrungduc1410
thg 11 14, 2020 2:01 SA

@spaussio

Ở cửa sổ terminal chạy laravel echo server của bạn in ra là gì tại thời điểm xảy ra lỗi, ở tab có lỗi bạn thử F5 để xem laravel echo server in ra gì nhé

Avatar
@laudaikinhdi
thg 1 25, 2021 8:58 SA

Xem giùm mình lỗi gì với bạn Vue.prototype.$io = require('socket.io-client');

Vue.prototype.Echo = new Echo({ broadcaster: 'socket.io', host: `{process.env.MIX_APP_URL}:6001`, }); Screen Shot 2021-01-25 at 15.57.29.png

Xem thêm (5)
Avatar

lạ nhỉ, bạn thử thêm đoạn sau vào cuối file bootstrap.js xem nhé:

window.axios.interceptors.request.use((config) => {
  config.headers['X-Socket-ID'] = window.Echo.socketId() // Echo instance
  // the function socketId () returns the id of the socket connection
  return config
})
Avatar
@laudaikinhdi
thg 1 27, 2021 7:51 SA

@maitrungduc1410 Fix được rồi. tks bạn Sẳn tiện cho mình hỏi. Mình dùng api (passport để login) thì "authEndpoint": "/broadcasting/auth" chổ này có cần thay đổi j k bạn

Avatar
@Mario
thg 6 11, 2021 1:59 SA

Mình chat realtime rồi, nhưng bị gặp vấn đề: Khi 1 user (1) thoát ra room, user (2) vẫn thấy user (1) đang online. Mình check nhưng chưa tìm ra cách fix, bạn xem giúp ạ Screenshot from 2021-06-11 08-56-40.png

Xem thêm (2)
Avatar
@Mario
thg 6 11, 2021 2:52 SA

Sorry bạn, mình fix được rồi nhé. Thiếu phần destroy khi mình rời kênh. Nghĩ lại sai cơ bản quá : )))

Avatar

@Mario okie bạn nhé

Avatar
@dangtai0512
thg 7 3, 2021 5:59 SA

image.png cho mình hỏi tại sao mình gửi tin nhắn riêng cho user mà user đó k hiển thị thông báo có tin nhắn mới vậy ạ

Avatar

bạn xem logics của mình nhận tin nhắn chát riêng từ user khác ở đây nhé:

https://github.com/maitrungduc1410/realtime-chatapp-laravelecho-socketio/blob/docker-non-root/resources/js/pages/Room.vue#L136-L149

Avatar
@Longkma
thg 12 14, 2021 8:24 SA
Avatar
@Longkma
thg 12 14, 2021 12:20 CH

Chào anh. Em đang gặp vấn đề là khi send message thì bên vue không listen được ạ image.png image.png image.png image.png image.png image.png

socket thì em check vẫn chạy bình thường ạ. Chưa tìm ra lỗi ở đâu. Log ở listen bên vue không thấy vào ạ

Avatar

ở cửa sổ laravel-echo-server ko có message thông báo join channel kìa e ơi -> chứng tỏ từ frontend (Vue) , nó chưa join thanhf công vào channel nên sẽ ko có realtime j cả là đúng rồi,

đầu tiên và trước hết nó phải show được message như sau khi mà bên vue gọi Echo.private.... nhé:

08b7050c-877f-4fa1-b8aa-6fe0dbb7ccc5.png

Đừng nói với a là cái if trong mounted ko bao giờ chạy vào nhé e 😃

Avatar
@DucMinhViblo
thg 3 8, 2022 3:21 CH

Screenshot 2022-03-08 221827.png Chào a Mai Trung Đức, e gặp sự cố là khi gửi tin nhắn thì nó ko nhận được event, nhưng queue vẫn xử lý chạy, thành ra là không có chat realtime, e cần a giúp đỡ ạ

Xem thêm (3)
Avatar
@DucMinhViblo
thg 3 9, 2022 8:37 SA

@maitrungduc1410 Dạ, bài viết của a bổ ích lắm ạ👍️, Cảm ơn anh!

Avatar

@DucMinhViblo thanks e đã theo dõi 😃

Avatar
@hientm
thg 3 29, 2023 4:14 SA

image.png image.png image.png cái này là bị sao hả a ?

Xem thêm (3)
Avatar
@Lazyboy
thg 4 6, 2023 4:07 SA

@hientm mình cũng bị lỗi tương tự như bạn, bạn fix được chưa ạ

Avatar

mình đã kiểm tra lại và mọi thứ vẫn chạy bình thường các bạn nhé, các bạn check lại:

  • laravel-echo-server.json thì authHost phải là http://localhost:8000
  • đã chạy php artisan serve hay chưa, chưa chạy là sẽ bị lỗi ECONNREFUSED
  • có chính xác là app Laravel của các bạn đang chạy ở http://localhost:8000? Mở trình duyệt ở địa chỉ đó xem app lên chưa nhé.
  • Laravel echo Server và app Laravel đang có chạy trên cùng 1 môi trường hay không, bởi vì ta đang config mọi thứ đều là localhost mình vừa trực tiếp follow lại từ đầu bài và kết quả vẫn oke:

Screenshot 2023-04-26 at 11.22.13 AM.png

Avatar
@quangduc123
thg 9 30, 2023 9:32 SA

Chào a, bài viết rất hay ạ. E có 1 thắc mắc là khi mình thoát ra khỏi trang nhắn tin thì có cần disconnect realtime không? Nếu để vậy thì có tốn tài nguyên và ảnh hưởng tới tốc độ xử lý của hệ thống không?

Avatar

e nên disconnect khi ra khỏi trang nhắn tin nhé, như vậy thì server sẽ không cần bắn message về cho client nữa, vì lúc đó client không ở màn message nên không để làm gì.

Khi nào user quay lại màn nhắn tin thì kết nối lại không tốn tài nguyên lắm và ảnh hưởng mấy đâu e ạ, ko đáng kể. Việc ko disconnect để server phải bắn message về còn tốn hơn ấy chứ, nhất là khi số lượng client nhiều lên, server phải broadcast nhiều rất nặng

Avatar
@quangduc123
thg 10 1, 2023 3:05 SA

@maitrungduc1410 e hiểu rồi, cảm ơn a

Avatar

Hello bạn, mk đang muốn tách ra 2 project BE + FE nhưng đang ko join đc channel. b giúp mk đc ko

Avatar
@BinhAn
thg 4 16, 2024 7:47 SA

nếu dùng react tạo riêng không dùng chung với laravel thì : <script src="http://localhost:6001/socket.io/socket.io.js"></script> và những config trong boststrap.js làm sao anh

Avatar
@maitrungduc1410
thg 4 16, 2024 10:55 SA

như vậy thì e nên dùng api middleware để lấy jwt cho React, dùng token đó gửi từ React tới laravel echo server để auth, xem bài xác thực với Passport trong series này a đã viết về cái này rồi nhé

Avatar
@cutchienbo
thg 8 3, 2024 8:17 CH

Screenshot 2024-08-04 031234.pngScreenshot 2024-08-04 031309.pngScreenshot 2024-08-04 031347.pngScreenshot 2024-08-04 031415.pngEm sử dụng socket.io thay cho pusher và gặp vấn đề là broadcast::channel không chạy, em đã return false ở channel rồi nhưng kênh vẫn được xác thực thành công. Nhờ a xem giúp với ạ.Screenshot 2024-08-04 031222.png

Avatar

e để log vào tất cả những chỗ kia xem nó có chạy hay ko?

Avatar
+19
Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí