首頁  >  文章  >  php框架  >  Laravel 之 廣播 模組詳解

Laravel 之 廣播 模組詳解

藏色散人
藏色散人轉載
2020-04-12 14:12:313883瀏覽

本文是基於Laravel 5.4版本的廣播模組程式碼進行分析書寫;

推薦:《laravel教學

簡介

Laravel 之 廣播 模組詳解

#廣播是指發送方發送訊息,訂閱頻道的各個接收方都能及時收到訊息;例如A同學寫了一篇文章,這時候B同學在文章底下評論了,A同學在頁面上是不用刷新就能收到提示有文章被評論了,這個本質上就是A同學收到了廣播訊息,這個廣播訊息是由B同學評論這個動作觸發了發送廣播訊息;

在整個廣播行為中,有一個重要的概念叫做頻道channel,頻道的型別有

● 公共頻道public

● 私有頻道private

● 存在頻道presence

行動端訂閱了公用頻道public,會直接提示成功;私人頻道private和存在頻道presence在進行訂閱的過程中,會向伺服器端發送權限驗證,看是不是有權限可以訂閱該頻道;私有頻道private和存在頻道presence的差異在於,私有頻道private能夠接收其他成員發送的訊息,而存在頻道presence除此之外,還能夠在用戶的加入與離開時接收訊息;

廣播適合以下場景(此小部分摘自基於Pusher 驅動的Laravel 事件廣播(上)):

● 通知(Notification) 或訊號(Signal)

通知是最簡單的範例,也最常使用到。訊號也可視為通知的一種展現形式,只不過訊號沒有UI而已。

● Activity Streams

Activity Streams(feeds)是社群網路的核心。如微信朋友圈的點讚和評論,A可以即時看到B的點贊,B可以即時看到A的評論。

● 聊天

聊天訊息的即時顯示

模組組成

Demo

日誌驅動程式

設定

.env檔案修改或新增一行:BROADCAST_DRIVER=log;

廣播

直接呼叫

 $manager = app(Illuminate\Broadcasting\BroadcastManager::class);
 $driver = $manager->connection();
 // 第一个参数是频道名,第二个参数是事件名,第三个参数是广播内容
 $driver->broadcast(['channel_1', 'channel_2'], 'login', ['message' => 'hello world']);

因為是日誌驅動,所以廣播內容會寫到框架配置的日誌文件中,輸出訊息如下所示

[2017-08-18 20:45:49] local.INFO: Broadcasting [login] on channels [channel_1, channel_2] with payload:
{
    "message": "hello world"
}

監聽事件廣播

#這種呼叫方式,是當實作ShouldBroadcast介面的事件被觸發時,則會進行廣播操作;(同時,還有一個介面叫ShouldBroadcastNow,與ShouldBroadcast介面的不同在於,將實作ShouldBroadcastNow介面的事件放入佇列時,會被放入叫sync的佇列)

舉個例子, 第一步,Illuminate\Auth\Events\Login事件是使用者登入成功後會觸發的事件,略作改動,讓其實現廣播功能;

class Login implements ShouldBroadcast {
    ......
    
    // 定义事件被触发时,广播频道;此处定义名为 first-channel 的私有频道
    public function broadcastOn() {
        return [
            new PrivateChannel('first-channel'),
        ];
    }
    
    // 自定义广播名称;如果方法未定义,默认以类名为事件名,此处的默认值是 Illuminate\Auth\Events\Login
    public function broadcastAs() {
        return 'login';
    }
}

第二步,註冊事件監聽;在app/Providers/EventServiceProvider.php中修改:

protected $listen = [
   ......
   'Illuminate\Auth\Events\Login' => [
        'App\Listeners\UserLogin',
   ],
];

檔案app/Listeners/UserLogin.php粗糙地實現了一下:

class UserLogin {
    public function __construct() {}
    
    public function handle(Login $event){
        \Log::info('Do UserLogin Listener: I was Login');
    }
}

第三步,觸發事件,發送廣播;有好幾種觸發廣播方式:1.直接事件觸發

event(new Illuminate\Auth\Events\Login($user, true));

2.幫助函數broadcast,間接觸發事件

broadcast(new Illuminate\Auth\Events\Login($user, true));
3.廣播管理類,間接觸發事件,直接廣播

$manager = app(Illuminate\Broadcasting\BroadcastManager::class);
$manager->event(new Illuminate\Auth\Events\Login($user, true));

4.廣播管理類,間接觸發事件,放入隊列

$manager = app(Illuminate\Broadcasting\BroadcastManager::class);
$manager->queue(new Illuminate\Auth\Events\Login($user, true));

Pusher驅動

###Pusher是一個第三方服務,伺服器發送廣播時,會向Pusher發送請求,再透過Pusher與瀏覽器或行動端保持的長連線進行資料互動;#########設定######## #透過Pusher官網註冊用戶信息,獲取屬於自已的一套密鑰信息,修改.env的配置文件;###
BROADCAST_DRIVER=pusher
PUSHER_APP_ID=xxxxxxxxxxxxxxxxxxxxxx
PUSHER_APP_KEY=xxxxxxxxxxxxxxxxxxxxxx
PUSHER_APP_SECRET=xxxxxxxxxxxxxxxxxxxxxx
######準備工作############事件監聽#########後台的事件監聽還是採用"日誌驅動"部分的登入範例;########前端########前端頁面引入以下程式碼: ###
<script src="https://js.pusher.com/4.1/pusher.min.js"></script>
<script>
// 打开 Pusher 的调试日志
Pusher.logToConsole = true;
// 定义 Pusher 变量
var pusher = new Pusher(&#39;PUSHER_APP_KEY的值&#39;, {
    cluster: &#39;ap1&#39;,
    encrypted: true
});
// 定义频道,绑定事件
var channel = pusher.subscribe(&#39;private-first-channel&#39;);
channel.bind(&#39;login&#39;, function(data) {
    alert(data);
});
</script>
###如果訂閱的是公共頻道,則不會向伺服器端請求權限檢查;如果是私有頻道(頻道名稱是以private-開頭)或存在頻道(頻道名稱是以presence-開頭),則會發出權限檢查請求;對應的後端需要定義私有頻道和存在頻道的權限;#########頻道權限定義#########頻道的權限定義是在routes/ channels.php裡;此處筆者為first-channel頻道定義權限回呼函數:###
Broadcast::channel(&#39;first-channel&#39;, function ($user) {
    return (int) $user->id === 1;
});
###有讀者會疑問,前端頁訂閱的頻道不是private-first-channel嗎?怎麼後端只定義first-channel頻道的權限呢?那是因為,後端定義的頻道假設是A,那麼在Pusher及瀏覽器端或行動端傳遞的私有頻道名為private-A,存在頻道則會是presence-A;######## #廣播############直接廣播######
$manager = app(Illuminate\Broadcasting\BroadcastManager::class);
$driver = $manager->connection();
// socket 参数是广播私有频道时排除的 socket, 每个浏览器端或者移动端在建立 websocket 时都会被分配一个 socket_id
$driver->broadcast([&#39;private-first-channel&#39;], &#39;login&#39;, [&#39;user&#39; => [&#39;name&#39; => &#39;hello&#39;], &#39;socket&#39; => &#39;5395.4377611&#39;]);
#######間接廣播#########參考「日誌驅動」提及的間接廣播方式;###

如果要發送排我廣播(也就是除了目前請求的這個客戶端不收到廣播訊息),則需要以下條件:

1.事件使用Illuminate\Broadcasting\InteractsWithSockets trait;

2.前端傳送過來的請求頭要攜帶X-Socket-ID訊息;

3.事件觸發執行broadcast(new Illuminate\Auth\Events\Login($user, true)) ->toOthers();

Redis驅動程式

#設定

.env檔案修改或新增一行:BROADCAST_DRIVER= redis;

廣播

原理是同樣在後端部署一個Socket.IO伺服器,Laravel框架會發布訊息到Socket.IO伺服器上,由Socket.IO伺服器同瀏覽器端或行動端保持長連線;

這部分筆者尚未demo,網路入門資料還挺多的,知道原理,這部分動作上手就容易多了;

以上是Laravel 之 廣播 模組詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除