使用laravel广播推送消息
项目是基于laravel6开发的一个论坛项目,里面有公告和私信功能,需求要求做到实时推送
方案
- 使用php socket 搭建
- 使用laravel自带的广播
php socket在laravel中使用搭建起来比较麻烦,而且要封装函数,对于一个小功能来说成本太高,决定使用laravel自带的广播功能来实现
laravel广播驱动类型
- pusher
- 官方默认的,收费
- redis
- 可搭配socket.io使用
最终方案
使用laravel广播基于redis驱动搭配socket.io实现该功能
因为要使用node.js安装相关包,要先安装node.js
- 打开laravel默认关闭的广播服务
config\app.php
- 注释掉redis配置里的前缀设置(laravel中默认有前缀)
config'database.php
- 修改
.env
文件中的修改广播驱动为redis
4.安装laravel中redis扩展,这里以predis为列
composer require predis/predis
安装完成后设置.env
中的REDIS_CLIENT
设置为predis
如果不想设置,可以调整config\database.php
中的clinet
默认为predis
- 安装依赖
// 更新依赖
npm install
//安装负责处理socket的node.js包
npm install -g laravel-echo-server
//安装前端事务处理包
npm install --save socket.io-client
npm install --save laravel-echo
//运行socket服务
laravel-echo-server init
//启动
laravel-echo-server start
运行成功
- 查看npm安装包
- 创建一个event
php artisan make:event TestEvent
代码如下
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class TestEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($test)
{
//
$this->message = $test;
}
// 广播频道
public function broadcastOn()
{
// return new PrivateChannel('channel-name');
return new Channel('test_public_channel');
}
// 广播内容
public function broadcastWith()
{
return [
'data' => $this->message
];
}
// 广播事件名称,默认为 App\Events\TestEvent
public function broadcastAs()
{
return 'TestEvent';
}
// 决定是否广播的条件
public function broadcastWhen()
{
if ('test') {
return true;
}
}
}
- 前端接收广播
//需要加入token 广播强制要求
<meta name="csrf-token" content="{{ csrf_token() }}">
//引入socket.io.js
<script src="//{{ Request::getHost() }}:6001/socket.io/socket.io.js"></script>
<script type="module">
//在js中引入echo.js
import Echo from '/static/echo.js';
//初始化echo
window.Echo = new Echo({
broadcaster: 'socket.io',
host: 'http://' + window.location.hostname + ':6001'
});
//公共频道
window.Echo.channel('test_public_channel')
.listen('.TestEvent', (e) => { // 注意,如果在laravel事件中用broadcastAs方法设置了广播事件名称,则这里监听的事件名称前要加"."。
console.log(e);
});
</script>
注:如果找不到echo.js文件,在项目下node_modules\laravel-echo\dist
找到echo.js
复制到对应的目录下即可
- 调用方法
broadcast(new TestEvent('你的文章被点赞了'));
前端收到对应消息
- 私有频道
推送消息是时候用到了私有频道,操作如下:
- 创建一个私有频道的event
php artisan make:event PrivateEvent
,代码如下:
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class PrivateEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
protected $user_id;
protected $info;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($user_id,$info)
{
$this->user_id =$user_id;
$this->info = $info;
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('user-'.$this->user_id);
}
public function broadcastAs()
{
return 'PrivateEvent';
}
public function broadcastWith()
{
$data = ['id'=>$this->user_id,'type'=>$this->info['type'],'message'=>$this->info['message']];
return ['data'=>$data];
}
}
2.在路由channel.php
中设置如下内容
//这里的意思只有前端用户才有权限
Broadcast::channel('user-.{user_id}', function ($user_id, $data) {
return true;
},['guards'=>'web']);
3.前端代码
//需要加入token 广播强制要求
<meta name="csrf-token" content="{{ csrf_token() }}">
//引入socket.io.js
<script src="//{{ Request::getHost() }}:6001/socket.io/socket.io.js"></script>
<script type="module">
//在js中引入echo.js
import Echo from '/static/echo.js';
//初始化echo
window.Echo = new Echo({
broadcaster: 'socket.io',
host: 'http://' + window.location.hostname + ':6001'
});
//调用私有频道监控
window.Echo.private("user-{{auth()->id()}}")
.listen('.PrivateEvent', (e) => {// 注意,如果在laravel事件中用broadcastAs方法设置了广播事件名称,则这里监听的事件名称前要加"."。
console.log(e);
})
</script>