laravel广播系统

  • laravel6 基于 Redis 实现广播系统上(公共频道)
  • 启动websocket服务端
  • 私有频道
  • 注意事项一定要看
  • 生成事件
  • 修改resource/bootstrap.js代码如下
  • 私有频道认证与授权
  • 分发私有频道事件消息
  • 浏览器分别打开
  • supervisor守护进程
  • 安装supervisor
  • 后台运行laravel-echo-server
  • 注意
  • 关于报错


laravel6 基于 Redis 实现广播系统上(公共频道)

laravel6 基于 Redis 实现广播系统上(公共频道).

启动websocket服务端

npm run watch
laravel-echo-server start

私有频道

注意事项一定要看

注释掉 config/database.php 中 redis.options.prefix

'redis' => [

        'client' => env('REDIS_CLIENT', 'phpredis'),

        'options' => [
            'cluster' => env('REDIS_CLUSTER', 'redis'),
            //'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
        ],

因为 Laravel Echo 目前没有提供这个前缀设置,而 window.Echo.private 方法会在频道名称前面加上 private- 前缀,这会导致后端和前端的频道名称不一致(后端是 laravel_database_private-user.1,前端是 private-user.1),除了取消 Redis 前缀设置,目前这个问题无解

生成事件

php artisan make:event PrivateMsgEvent

代码如下:

<?php

namespace App\Events;

use App\Models\Admin\User;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class PrivateMsgEvent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $user;
    public $userId = '';

    /**
     * PrivateMsgEvent constructor.
     * @param User $user
     */
    public function __construct(User $user)
    {
        //
        $this->user = $user;
        $this->userId = 1;
    }

    /**
     * @return Channel|Channel[]|PrivateChannel
     */
    public function broadcastOn()
    {
        return new PrivateChannel('user.'. $this->userId);
    }
}
修改resource/bootstrap.js代码如下
import Echo from "laravel-echo"

window.io = require('socket.io-client');

window.Echo = new Echo({
    broadcaster: 'socket.io',
    //私有频道授权接口 我这里是 api + jwt 
    authEndpoint: '/api/broadcasting/auth',
    host: window.location.hostname + ':6001',
    auth: {
        headers: {
        	//这里是 Bearer 令牌 用于登陆授权
            Authorization: 'Bearer ' + 'eyJ0eXtiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sYXJhdmVsZGVtby5jb21cL2FkbWluXC91c2VyXC9sb2dpbiIsImlhdCI6MTYxNDc1MjUwMSwiZXhwIjoxNjE1MzU3MzAxLCJuYmYiOjE2MTQ3NTI1MDEsImp0aSI6IjJlWHJ2ZDcyekVURmt1THEiLCJzdWIiOjEsInBydiI6IjcyM1Q5YWZmZGEwNDRkYzJhZDcwYTM5ZWYxNTE2M2VhNjdhNzMzMTMiLCJyb2xlIjoiYWRtaW4ifQ.hdDTJaGDB7dr7D1MGx80Pg6nS0ckmYX7wydOwU9onN8'
        },
    },
});

window.Echo.channel('public-msg-event')
    //注释了前缀 laravel_database_public-msg-event 改为了 public-msg-event
    .listen('PublicMsgEvent', (e) => {  //PublicMsgEvent就是之前生成的文件
        var msg =e.msg;
        console.log(msg);
    });
window.Echo.private('user.1')
    .listen('PrivateMsgEvent', (e) => {
        console.log('userId:'+e.userId);
    });

私有频道认证与授权

私有频道需要用户已认证并且对用户进行授权后才能订阅并接收广播消息,这个时候广播路由就派上用场了,我们可以在 routes/channels.php 中注册这个私有频道的广播路由来定义授权策略:

<?php
use Illuminate\Support\Facades\Broadcast;
//guards 根据自己config/auth.php 中 guards 填写 
Broadcast::channel('user.{userId}', function ($user, $userId) {
    return true;
}, ['guards' => ['admin']]);

修改app/Providers/BroadcastServiceProvider.php

public function boot()
{
	//Broadcast::routes();
	//我这里是api+jwt 不这样配置就会报错 CSRF token mismatch.
    Broadcast::routes(['middleware' => ['auth:admin']]);

    require base_path('routes/channels.php'); #加载检查权限的广播路由
}

分发私有频道事件消息

修改routes/web.php

<?php

use Illuminate\Support\Facades\Route;
use App\Events\PublicMsgEvent;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});

Route::get('/PublicMsgEvent', function () {
    $str = \Illuminate\Support\Str::random(10);
    //event(new PublicMsgEvent('PublicMsgEvent'));
    broadcast(new PublicMsgEvent($str));
});

Route::get('/PrivateMsgEvent', function () {
    $user = User::query()->findOrFail(1);
    broadcast(new PrivateMsgEvent($user));
});

浏览器分别打开

http://laraveldemo.com/

http://laraveldemo.com/PrivateMsgEvent 是触发消息
访问http://laraveldemo.com/PrivateMsgEvent

redis 通道号 redis 频道_laravel

supervisor守护进程

安装supervisor

后台运行laravel-echo-server

#得到node路径 /path/to/node
which node 
#得到laravel-echo-server路径 /path/to/laravel-echo-server
which laravel-echo-server
ln -s /path/to/node /usr/bin/node

配置文件如下

[program:laravelEchoServer]
;运行脚本
command=/path/to/laravel-echo-server start
;运行目录
directory=/www/wwwroot/laraveldemo.com/
;自动启动
autostart=true
;自动重启
autorestart=true
startsecs=5
startretries=3
;输出
stdout_logfile=/www/log/laravelEchoServer.out.log
;错误日志
stderr_logfile=/www/log/laravelEchoServer.err.log
;用户
user=root
priority=999
numprocs=1
process_name=%(program_name)s_%(process_num)02d

注意

主要看command 和 directory 两行
一般开启laravel-echo-server 只需要laravel-echo-server start 但是 supervisor 必须写成绝对路径
指令 which laravel-echo-server 获取自己服务器上laravel-echo-server的绝对路径
directory运行目录

关于报错

在使用supervisorctl status查看时报

BACKOFF Exited too quickly (process log may have details)

查看配置stderr_logfile错误日志

tail -f /www/log/laravelEchoServer.err.log

/usr/bin/env: node: No such file or directory

解决办法为:

#得到node路径 /path/to/node
which node 
#得到laravel-echo-server路径 /path/to/laravel-echo-server
which laravel-echo-server
#创建软链
ln -s /path/to/node /usr/bin/node

最后重启supervisor查看是否成功