pusher 创建新应用_基于 Laravel + Pusher + Vue 通过事件广播构建实时聊天室应用
基于 Laravel + Pusher + Vue 通過事件廣播構建實時聊天室應用
由 學院君 創建于2年前, 最后更新于 3個月前
版本號 #3
前言:學院君之前有說過要整理出一篇事件廣播手把手教程,今天終于兌現了,本教程基于 Laravel + Pusher + Vue,以事件廣播作為核心技術,從零開始讓你在幾分鐘內即可搭建起一個實時聊天室應用。不多廢話,直接上手吧。
應用初始化
安裝配置
首先還是通過 Composer 安裝一個全新的聊天室應用:
composer create-project laravel/laravel chatroom --prefer-dist
由于要用到事件廣播,所以需要取消 config/app.php 中廣播服務提供者前面的注釋:
修改 .env 中 BROADCAST_DRIVER 配置項為 pusher:
BROADCAST_DRIVER=pusher
盡管 Laravel 開箱支持 Pusher,但是我們還是需要安裝對應的 PHP SDK:
composer require pusher/pusher-php-server
設置 Pusher 憑證信息
訪問 Pusher 官網,注冊并登錄到用戶后臺,創建一個新的 Channels App:

創建完成后即可在跳轉頁面中獲取到 App Keys 相關信息:

將對應字段填充到聊天室應用根目錄下的 .env 相應配置項即可。
前端資源初始化
我們使用 Laravel Mix 來編譯前端 CSS 和 JavaScript:
npm install
此外,Laravel 還提供了 JavaScript 庫 Laravel Echo 來訂閱和監聽事件:
npm install --save laravel-echo pusher-js
安裝完成,還要告知 Laravel Echo 使用 Pusher,Laravel 已經在 resources/assets/js/bootstrap.js 中為我們提供了該實現,只不過默認注釋起來了,只需要取消這段注釋即可:
import Echo from 'laravel-echo'
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
encrypted: true
});
用戶認證腳手架代碼
我們設定只有登錄用戶才能進入聊天室進行聊天,為了簡化流程,我們使用 Laravel 默認的用戶認證功能:
php artisan make:auth
上述命令會為我們生成用戶認證系統所必須的路由、視圖、控制器等代碼。在功能生效之前,還需要運行數據庫遷移命令生成對應數據表,編輯 .env 中數據庫相關配置項,保證可以正確連接上數據庫,然后運行以下命令:
php artisan migrate
至此,應用初始化準備工作已完成,下面開始編寫業務代碼。
業務代碼實現
消息模型
首先要為發送的消息創建一個模型類及其對應數據庫遷移文件:
php artisan make:model Message -m
在新生成的 app/Messaage 模型類中新增下面這行代碼以方便批量賦值:
/**
* Fields that are mass assignable
*
* @var array
*/
protected $fillable = ['message'];
然后在 databases/migrations 目錄下編寫剛生成的 messages 對應遷移文件的 up 方法:
Schema::create('messages', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->text('message');
$table->timestamps();
});
最后執行遷移命令生成數據表 messages:
php artisan migrate
用戶與消息的關聯關系
很顯然,用戶與消息之間是一對多的關系,在 User 模型類中新增關聯方法:
/**
* A user can have many messages
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function messages()
{
return $this->hasMany(Message::class);
}
接下來在 Message 模型類中定義與之相對的關聯關系:
/**
* A message belong to a user
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
return $this->belongsTo(User::class);
}
控制器代碼
創建控制器 ChatsController 實現具體業務邏輯:
php artisan make:controller ChatsController
編寫剛生成的控制器類 app/Http/Controllers/ChatsController 代碼如下:
namespace App\Http\Controllers;
use Auth;
use App\Message;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class ChatsController extends Controller
{
public function __construct()
{
$this->middleware('auth'); // 登錄用戶才能訪問
}
/**
* Show chats
*
* @return \Illuminate\Http\Response
*/
public function index()
{
return view('chat');
}
/**
* Fetch all messages
*
* @return Message
*/
public function fetchMessages()
{
return Message::with('user')->get();
}
/**
* Persist message to database
*
* @param Request $request
* @return Response
*/
public function sendMessage(Request $request)
{
$user = Auth::user();
$message = $user->messages()->create([
'message' => $request->input('message')
]);
return ['status' => 'Message Sent!'];
}
}
該控制器提供了三個業務方法,index 用于顯示聊天室視圖,fetchMessages 用戶獲取所有消息,sendMessage 用于發送消息。
注冊應用路由
對應地,我們在 routes/web.php 中注冊三個路由:
Route::get('/', 'ChatsController@index');
Route::get('messages', 'ChatsController@fetchMessages');
Route::post('messages', 'ChatsController@sendMessage');
從注冊路由中移除 /home 路由,相應地,需要把 app/Http/Controllers/Auth/LoginController.php 和 app/Http/Controllers/Auth/RegisterController.php 中的 $redirectTo 屬性進行調整:
protected $redirectTo = '/';
聊天室視圖
對于聊天室視圖代碼,我們基于 Bootsnipp 聊天室代碼片段 稍作調整。首先創建 resources/views/chat.blade.php:
@extends('layouts.app')
@section('content')
聊天室v-on:messagesent="addMessage"
:user="{{ Auth::user() }}"
>
@endsection
該視圖用于展示聊天室主體頁面。注意到我們在視圖中使用了一些 Vue 組件,chat-messages 組件用于顯示所有聊天信息,chat-form 組件用于發送消息,稍后會給出這些組件代碼。
在編寫 Vue 組件之前,我們在 resources/views/layouts/app.blade.php 模板中為 chat 視圖添加一些樣式代碼(添加到 標簽之前):
.chat {
list-style: none;
margin: 0;
padding: 0;
}
.chat li {
margin-bottom: 10px;
padding-bottom: 5px;
border-bottom: 1px dotted #B3A9A9;
}
.chat li .chat-body p {
margin: 0;
color: #777777;
}
.panel-body {
overflow-y: scroll;
height: 350px;
}
::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
background-color: #F5F5F5;
}
::-webkit-scrollbar {
width: 12px;
background-color: #F5F5F5;
}
::-webkit-scrollbar-thumb {
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
background-color: #555;
}
接下來在 resources/assets/js/components 中創建 ChatMessages.vue 組件:
{{ message.user.name }}
{{ message.message }}
export default {
props: ['messages']
};
然后在同一目錄下創建 ChatForm.vue 組件:
發送
export default {
props: ['user'],
data() {
return {
newMessage: ''
}
},
methods: {
sendMessage() {
this.$emit('messagesent', {
user: this.user,
message: this.newMessage
});
this.newMessage = ''
}
}
}
最后我們需要將這兩個組件注冊到位于 resources/assets/js/app.js 中的 Vue 根實例中:
require('./bootstrap');
window.Vue = require('vue');
Vue.component('chat-messages', require('./components/ChatMessages.vue'));
Vue.component('chat-form', require('./components/ChatForm.vue'));
const app = new Vue({
el: '#app',
data: {
messages: []
},
created() {
this.fetchMessages();
},
methods: {
fetchMessages() {
axios.get('/messages').then(response => {
this.messages = response.data;
});
},
addMessage(message) {
this.messages.push(message);
axios.post('/messages', message).then(response => {
console.log(response.data);
});
}
}
});
廣播消息發送事件
為了在聊天室中進行實時交互,需要廣播某些事件,在本例中,我們會在用戶發送消息時觸發 MessageSent 事件:
php artisan make:event MessageSent
編寫 app/Events/MessageSent 事件類代碼如下:
namespace App\Events;
use App\Message;
use App\User;
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 MessageSent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* User that sent the message
*
* @var User
*/
public $user;
/**
* Message details
*
* @var Message
*/
public $message;
/**
* Create a new event instance.
* @param User $user
* @param Message $message
* @return void
*/
public function __construct(User $user, Message $message)
{
$this->user = $user;
$this->message = $message;
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('chat');
}
}
由于只有登錄用戶才能訪問我們的應用,所以我們定義了一個私有的頻道 chat,只有登錄用戶才能連接上它。
接下來,我們需要修改 ChatsController 的 sendMessage() 來廣播 MessageSent 事件:
public function sendMessage(Request $request)
{
$user = Auth::user();
$message = $user->messages()->create([
'message' => $request->input('message')
]);
broadcast(new MessageSent($user, $message))->toOthers();
return ['status' => 'Message Sent!'];
}
然后在 routes/channels.php 中授權當前登錄用戶可以監聽該私有頻道:
Broadcast::channel('chat', function ($user) {
return Auth::check();
});
現在,當一條消息發送后,MessageSent 事件就會被廣播到 Pusher,使用 toOthers() 是為了將消息發送者從廣播接收者中排除。
監聽消息發送事件
MessageSent 事件在服務端被廣播后,需要在客戶端監聽這個事件以便將最新發送消息更新到聊天室消息流中,我們可以通過在 resources/assets/js/app.js 中定義的 created() 方法中添加如下代碼片段來實現這一功能:
created() {
this.fetchMessages();
Echo.private('chat')
.listen('MessageSent', (e) => {
this.messages.push({
message: e.message.message,
user: e.user
});
});
},
我們通過 Laravel Echo 連接到 chat 頻道監聽 MessageSent 廣播事件,如果有新消息則將其推送到當前聊天室消息流中顯示。
在正式測試聊天室應用之前,還需要運行以下命令通過 Laravel Mix 來編譯前面編寫的 JavaScript 代碼:
npm run dev
使用示例演示
完成上述所有業務代碼編寫工作后,接下來就是見證工作成果的時候了,在項目根目錄下運行如下命令啟動應用:
php artisan serve
然后在瀏覽器通過 http://127.0.0.1:8000/ 訪問應用,由于系統需要登錄后才能訪問,所以首先會跳轉到登錄頁面,我們需要先注冊一個新用戶(學院君1),注冊成功后頁面即跳轉到聊天室頁面,我們發送一條測試消息:
為了測試多個用戶聊天的效果,打開另一個瀏覽器或者在當前瀏覽器新開一個隱身窗口,還是重復上面的訪問注冊步驟(這次注冊用戶為 學院君2),注冊成功后跳轉到聊天室頁面,看到的效果和上圖一樣,我們發條消息試試:
可以看到兩個窗口消息是同步的,所以已經達到我們預期的實時聊天效果,實現了通過事件廣播構建實時聊天室的功能:
棒棒噠!
聲明:Pusher 是一個收費服務,免費版本最大支持同時 100 個連接,以及每天20萬消息量,拿來作為開發測試完全沒問題。
總結
以上是生活随笔為你收集整理的pusher 创建新应用_基于 Laravel + Pusher + Vue 通过事件广播构建实时聊天室应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我的编程之路点滴记录(二)
- 下一篇: 飞畅科技 POE供电交换机常见问题详解