1. 程式人生 > >隨筆---laravel廣播事件

隨筆---laravel廣播事件

目標效果:像QQ郵箱那樣,在收到伺服器通知的時候在頁面上主動彈出提示框。
這裡寫圖片描述

在很多場景中,我們不能等待伺服器做出響應,例如有些業務是需要人工進行處理的,可能耗時幾小時才有結果,但是我們又需要在有結果的時候及時收到回饋,那麼這裡有幾個選擇:1.手動重新整理2.前端迴圈ajax請求3.websocket。第一個不用說了吧,不太可能考慮,第二個的話伺服器壓力會很大,因為兩小時內一個瀏覽器就能發出成百上千次請求,使用者多的情況下處理請求量太大,所以這裡採用websocket的方法,我不知道qq郵箱是否也是用這種方法,但是在中小型網站中應用這種方法能做到差不多的效果。當然,廣播事件傳輸的僅僅是資料而已,你可以編寫前端js,在接收到伺服器資料的時候將資料包裝成任意需要的樣式。
參考資料:

https://segmentfault.com/a/1190000002921506
事前準備:redis、node、wamp/lamp環境、一個能用的laravel專案
—————————————————————————————————————————————————————
一、配置

config/broadcasting.php中,如下配置’default’ => env(‘BROADCAST_DRIVER’,’redis’),使用redis作為php和js的通訊方式。 config/database.php中配置redis的連線。

——————————————————————————————————————————————

二、定義一個廣播事件

根據Laravel文件的說明,想讓事件被廣播,必須讓Event類實現一個Illuminate\Contracts\Broadcasting\ShouldBroadcast介面,並且實現一個方法broadcastOn。broadcastOn返回一個數組,包含了事件傳送到的channel(頻道)。如下:

<?php

namespace App\Events;

use App\Events\Event;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting
\ShouldBroadcast; class SomeEvent extends Event implements ShouldBroadcast { use SerializesModels; public $user_id; public $m1; public $m2; /** * Create a new event instance. * * @return void */ public function __construct($user_id,$m1,$m2) { $this->user_id = $user_id; $this->m1 = $m1; $this->m2 = $m2; } /** * Get the channels the event should be broadcast on. * * @return array */ public function broadcastOn() { return ['test-channel:'.$this->user_id]; } }

tips:預設情況下,Event中的所有public屬性都會被序列化後廣播。上面的例子中就是$user_id這個屬性。你也可以使用broadcastWith這個方法,明確的指出要廣播什麼資料。例如:

 public function broadcastWith() {
     return ['user_id' => $this->user_id]; 
 }

——————————————————————————————————————————————

三、準備好前端view

這裡我把我的前端view程式碼寫出來,這裡要引用socket.io.js,算是一個引用庫?可以自己百度下載一個,我也忘了自己是哪裡弄來的了。我後續貼個度盤的連結把整個打包放上去好了。前端模板用的是bootstrap的toastr把資料輸出,當然你可以用其他的前端樣式,反正用你需要的方法和樣式把資料輸出就可以了

<html>
<head>

</head>
<body>
<link href="{{ asset('css/plugins/toastr/toastr.min.css')}}" rel="stylesheet">

<!-- Mainly scripts -->
<script src="{{ asset('js/jquery-2.1.1.js')}}"></script>
<script src="{{ asset('js/plugins/toastr/toastr.min.js')}}"></script>

<script src="{{ asset('js/socket.io-client/dist/socket.io.js')}}"></script>
<script>

    //toastr 配置
    toastr.options = {
        "closeButton": true,
        "debug": false,
        "progressBar": true,
        "preventDuplicates": false,
        "positionClass": "toast-top-right",
        "onclick": null,
        "showDuration": "400",
        "hideDuration": "1000",
        "timeOut": "7000",
        "extendedTimeOut": "1000",
        "showEasing": "swing",
        "hideEasing": "linear",
        "showMethod": "fadeIn",
        "hideMethod": "fadeOut"
    };

    var mapping = [];
    mapping['user_id'] = '使用者id';
    mapping['m1'] = '訊息1';
    mapping['m2'] = '訊息2';

    var socket = io('http://localhost:6001');
    socket.on('connection', function (data) {
        console.log(data);
    });
    socket.on('test-channel:3:App\\Events\\SomeEvent', function(message){
        console.log(message);
        var log = '';
        for(var i in message){
            log += mapping[i]+':'+message[i]+'<br>';
        }

        toastr.success(log,'您有一條新通知!');

    });
    console.log(socket);
</script>


</body>
</html>

——————————————————————————————————————————————
四、模擬觸發事件

因為是伺服器主動給客戶端發指令,那麼這裡就需要在你的業務流程裡面判斷什麼時候觸發資訊出去了
Event::fire(new \App\Events\SomeEvent(3,'qwe','asd'));

只要你處理完事務後,需要廣播,把這句話加在程式碼裡面就可以了
————————————————————————————————————————————————
五、啟動Redis和websocket伺服器

1.需要啟動一個Redis,事件廣播主要依賴的就是redis的sub/pub功能,具體可以看redis文件
~這裡開的是redis的redis-server.exe,不需要其他的操作,開啟就行了(不能關掉這個視窗)
2.需要啟動一個websocket伺服器來和client通訊,建議使用socket.io,程式碼如下:
~這裡是用node開啟下面的檔案(我命名是test.js),在命令列裡面cd進入你放這個test.js的位置,然後執行 node test.js 啟動它就行了(不能關掉這個視窗)

var app = require('http').createServer(handler);
var io = require('socket.io')(app);
var Redis = require('ioredis');
var redis = new Redis('6379', '127.0.0.1');
app.listen(6001, function() {
    console.log('Server is running!');
});
function handler(req, res) {
    res.writeHead(200);
    res.end('');
}
io.on('connection', function(socket) {
    console.log('connected');
});
redis.psubscribe('*', function(err, count) {
    console.log(count);
});
redis.on('pmessage', function(subscribed, channel, message) {
    console.log(subscribed);
    console.log(channel);
    console.log(message);
    message = JSON.parse(message);
    io.emit(channel + ':' + message.event, message.data);
});

3.好像還得開啟佇列(看了上面資料部落格的回覆,好像是看你 佇列配置是不是sync也就是同步模擬,我也不太清楚,反正這裡可能也需要用到佇列,我這裡是資料庫佇列,如果你發現觸發了event但是前端沒收到資訊的話,把佇列開啟試試看),進入你的laravel專案,然後在命令列輸入:

php artisan queue:listen

(不能關掉這個視窗)
————————————————————————————————
前端的那個socket.io庫,放到public相應的位置就能用了
http://pan.baidu.com/s/1kVIBHI3