使用 Laravel 广播事件实现基于 Socket.io 的实时消息通知

本文将基于 Laravel 5.5 + Vuejs 2.5.2 介绍使用 Laravel-echo-server.jsLaravel-echo.js 实现的 socket 服务

前置条件

开始使用

  • 指定事件广播驱动
    修改.env 配置项 BROADCAST_DRIVERredis
  • 创建消息通知

    确保 User Model 使用了 Notifiable 的 Trait

    php artisan make:notification TestNotification

  • 编辑 TestNotification

    修改 via 方法 return ['broadcast']

    因为 toArray 会同时被解析到 database , 而我们的通知可能和数据库中的存储不太一样,所以单独使用其 broadcast

    增加 toBroadcast 方法

    public function toBroadcast($notifiable)
    {
        return new BroadcastMessage([
            'message' => $this->data['message']
        ]);
    }

    完整的代码如下

    class Test extends Notification implements ShouldQueue
        {
                use Queueable;
    
                public $data;
    
                public function __construct($data = [])
                {
                        $this->data = $data;
                }
    
                public function via($notifiable)
                {
                        return ['broadcast'];
                }
    
                public function toBroadcast($notifiable)
                {
                        return new BroadcastMessage([
                                'message' => $this->data['message']
                        ]);
                }
        }
  • 安装 socket 服务端
    npm install -g laravel-echo-server
    安装完成后,在项目根目录执行 laravel-echo-server init 生成配置文件 , 具体参考 Laravel-echo-server
    最后,生成的文件大概类似:
    {
    "authHost": "http://sickle.dev",
    "authEndpoint": "/broadcasting/auth",
    "database": "redis",
    "databaseConfig": {
        "redis": {
            "port" : "6379",
            "host" : "127.0.0.1",
            "db" : 5
        },
        "sqlite": {
            "databasePath": "/database/laravel-echo-server.sqlite"
        }
    },
    "devMode": true,
    "host": null,
    "port": "6001",
    "protocol": "http",
    "socketio": {},
    "sslCertPath": "",
    "sslKeyPath": "",
    "sslCertChainPath": "",
    "sslPassphrase": "",
    "apiOriginAllow": {
        "allowCors": true,
        "allowOrigin": "http://localhost:1024",
        "allowMethods": "GET, POST",
        "allowHeaders": "Origin, Content-Type, X-Auth-Token, X-Requested-With, Accept, Authorization, X-CSRF-TOKEN, X-Socket-Id"
    }
    }

    可以参考我的配置,其中 authHost 为你当前项目的域名,allowOrigin 为允许跨域的域名,开发时建议设成 * 号

最后,执行 laravel-echo-server start 开启 socket 服务端

以下为前端部分

  • 安装 echo 客户端

为简单起见,我们使用一个第三方 vuevue-echo
main.js 里导入这个包

import Echo from 'vue-echo'
if(typeof io === 'function'){
    Vue.use(Echo, {
        broadcaster: 'socket.io',
        host: 'service.dev:6001',// 后端的URL + Laravel-echo-server 配置的端口号
        auth:{
            headers: {
                'Authorization': 'Bearer ' + getToken() // getToken前端自行实现
            }
        },
    });
}

在使用之前,最好将使用 socket 服务作为可选项。

然后,开启监听

if(typeof this.$echo !== 'undefined'){
    this.$echo.private(`App.Models.User.${this.user_info.user_id}`) //App.Models.User.1
    .notification((notification) => {
        if (notification.type === 'App\\Notifications\\TestNotification') { 
        console.log(notificaition) 
            let message = notification.message;
            let notify = this.$notify({
                title: '通知',
                dangerouslyUseHTMLString: true,
                message: message,
                type: 'info',
                onClick: () => {
                    notify.close();
                    this.$router.push({ name: 'xx' }) // 处理跳转到哪
                }
            });
        }
        })
}

如果不出意外,此时,已经可以监听到了。