Roy-Try-Catch
← Back to list

【Laravel】利用websocket製作聊天室

Roy • Updated 2026-02-27 11:03:43

本篇介紹如何在 Laravel 框架中,利用Websocket製作一個聊天室。

思考一下流程

登入→列表→加入聊天室→聊天室→傳送接收訊息(socket)

再來規劃一下大致需要Tables

users(會員)

rooms(聊天室)

user_room(會員跟聊天室的關聯)

messages(聊天訊息)

這裡範例是利用主機當socket

不想設定主機參數可以使用pusher

# 新增Project
laravel new {project}

修改env

# .env
BROADCAST_DRIVER=pusher
PUSHER_APP_ID=chat_room
PUSHER_APP_KEY=chatchatchat
PUSHER_APP_SECRET=chatchatchatchatchatchat

修改bootstarp.js

# /resources/js/bootstarp.js
import Echo from 'laravel-echo'
window.Pusher = require('pusher-js');
window.Echo = new Echo({
 broadcaster: 'pusher',
 encrypted: false,
 key: process.env.MIX_PUSHER_APP_KEY,
 cluster: process.env.MIX_PUSHER_APP_CLUSTER,
 wsHost: window.location.hostname,
 wsPort: 6001,
 forceTLS: false,
 disableStats: true
});

安裝套件

# 會員套件&啟用
npm install
composer require laravel/jetstream
php artisan jetstream:install livewire
npm run dev
# socket套件
composer install
composer require pusher/pusher-php-server ^4.1
npm install --save laravel-echo pusher-js 
composer require beyondcode/laravel-websockets
php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="migrations"
php artisan migrate
php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="config"

資料庫規劃

users

users

rooms

rooms

user_room

user_room

messages

messages

再來規劃broadcast的channel

至少在聊天室的時候要能及時推播訊息(根據room_id)

(以下為部分代碼)

app\Http\Controllers\MessageController

amespace App\Http\Controllers;

use App\Models\Room;
use App\Models\RoomJoin;
use App\Models\Message;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Events\RoomMessageChannelEvent;
use Carbon\Carbon;

class MessageController extends Controller
{
 /**
 * @var Room
 */
 public $model;

 /**
 * @var RoomJoin
 */
 public $join;

 /**
 * @var Message
 */
 public $message;

 /**
 * RoomController constructor.
 *
 * @param Room $room
 * @param RoomJoin $join
 * @param Message $message
 */
 public function __construct(Room $room, RoomJoin $join, Message $message)
 {
 $this->model = $room;
 $this->join = $join;
 $this->message = $message;
 }

 /**
 * @param \Illuminate\Http\Request $request
 * @param $id
 *
 * @Author: Roy
 * @DateTime: 2021/10/23 下午 12:15
 */
 public function store(Request $request, $id)
 {
 if ($this->checkRoomAndUser($id) === false) {
 return response()->json([
 'status' => false,
 'message' => '房間狀態有誤',
 'redirect_uri' => route('room.chat', ['id' => $id]),
 ]);
 }
 $this->message->create(
 [
 'user_id' => Auth::user()->id,
 'room_id' => $id,
 'date' => Carbon::now()->toDateString(),
 'content' => $request->get('content'),
 ]
 );
 broadcast((new RoomMessageChannelEvent(['user' => Auth::user(), 'content' => $request->get('content')], $id)));
 return response()->json([
 'status' => true,
 'message' => null,
 ]);
 }
}

app\event\RoomMessageChannelEvent

amespace 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 Illuminate\Support\Arr;
use Carbon\Carbon;

/**
 * Class RoomMessageChannelEvent
 *
 * @package App\Events\Rooms
 * @Author: Roy
 * @DateTime: 2021/10/21 下午 02:34
 */
class RoomMessageChannelEvent implements ShouldBroadcast
{
 use Dispatchable, InteractsWithSockets, SerializesModels;

 public $message;
 public $room_id;

 /**
 * RoomMessage constructor.
 *
 * @param $message
 * @param $room_id
 *
 * @Author: Roy
 * @DateTime: 2021/10/21 上午 11:54
 */
 public function __construct($message, $room_id)
 {
 $this->room_id = $room_id;
 $this->message = (object) [
 'user' => (object) [
 'id' => Arr::get($message, 'user.id'),
 'name' => Arr::get($message, 'user.name'),
 'image' => sprintf("https://ui-avatars.com/api/?name=%s&color=7F9CF5&background=EBF4FF",
 Arr::get($message, 'user.name')),
 ],
 'content' => Arr::get($message, 'content'),
 'time' => Carbon::now()->format('H:i'),
 ];
 }

 /**
 * Get the channels the event should broadcast on.
 *
 * @return \Illuminate\Broadcasting\Channel|array
 */
 public function broadcastOn()
 {
 return new PresenceChannel(sprintf("chat.%s", $this->room_id));
 }
}

javescript 使用laravel.echo,jquery,mustache

啟動websocket(預設port:6001)

# 預設port:6001
php artisan websockets:serve
//php artisan websockets:serve --port=6001

範例畫面

範例

github範本 :

https://github.com/cc711612/chat_room

範本 :

https://chat.usongrat.tw

參考文獻:

https://beyondco.de/docs/laravel-websockets/getting-started/introduction

https://learnku.com/docs/laravel/8.x/broadcasting/9388#presence-channels

Comments

No comments yet.

請先登入