随笔---laravel广播事件

本文介绍了如何使用Laravel广播事件配合WebSocket实现实时通知功能,以达到类似QQ邮箱的提醒效果。通过配置广播驱动、定义广播事件、前端视图设置、模拟触发事件以及启动Redis和WebSocket服务器,实现数据从服务器到客户端的实时推送。同时,提到了前端使用了socket.io.js库和bootstrap的toastr来展示数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目标效果:像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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值