前言
本文主要给大家介绍了关于laravel广播模块的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍:
注意:本文是基于laravel 5.4版本的路由模块代码进行分析书写;
简介
广播是指发送方发送一条消息,订阅频道的各个接收方都能及时收到消息;比如 a同学写了一篇文章,这时候 b同学在文章底下评论了,a同学在页面上是不用刷新就能收到提示有文章被评论了,这个本质上就是a同学收到了广播消息,这个广播消息是由b同学评论这个动作触发了发送广播消息;
在整个广播行为中,有一个重要的概念叫频道channel,频道的类型有
- 公共频道public
- 私有频道private
- 存在频道presence
移动端订阅了公共频道public,会直接提示成功;私有频道private和存在频道presence在进行订阅的过程中,会向服务器端发送权限验证,看是不是有权限可以订阅该频道;私有频道private和存在频道presence的区别在于,私有频道private能够接收其他成员发送的消息,而存在频道presence除此之外,还能够在用户的加入与离开时接收信息;
广播适合以下场景:
- 通知(notification) 或 信号(signal)
- 通知是最简单的示例,也最经常用到。信号也可看作是通知的一种展现形式,只不过信号没有ui而已。
- activity streams
- activity streams(feeds)是社交网络的核心。如微信朋友圈的点赞和评论,a可以实时看到b的点赞,b可以实时看到a的评论。
- 聊天
- 聊天信息的实时显示
模块组成
demo
日志驱动
配置
.env文件修改或添加一行:broadcast_driver=log
;
广播
直接调用
1
2
3
4
|
$manager = app(illuminate\broadcasting\broadcastmanager:: class );
$driver = $manager ->connection();
// 第一个参数是频道名,第二个参数是事件名,第三个参数是广播内容
$driver ->broadcast([ 'channel_1' , 'channel_2' ], 'login' , [ 'message' => 'hello world' ]);
|
因为是日志驱动,所以广播内容会写到框架配置的日志文件中,输出消息如下所示
1
2
3
4
|
[2017-08-18 20:45:49] local.info: broadcasting [login] on channels [channel_1, channel_2] with payload:
{
"message" : "hello world"
}
|
监听事件广播
这种调用方式,是当实现shouldbroadcast接口的事件被触发时,则会进行广播操作;(同时,还有一个接口叫shouldbroadcastnow,与shouldbroadcast接口的不同在于,将实现shouldbroadcastnow接口的事件放入队列中时,会被放入叫sync的队列中)
举个例子,
第一步,illuminate\auth\events\login事件是用户登录成功后会触发的事件,略作改动,让其实现广播功能;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
class login implements shouldbroadcast {
......
// 定义事件被触发时,广播频道;此处定义名为 first-channel 的私有频道
public function broadcaston() {
return [
new privatechannel( 'first-channel' ),
];
}
// 自定义广播名称;如果方法未定义,默认以类名为事件名,此处的默认值是 illuminate\auth\events\login
public function broadcastas() {
return 'login' ;
}
}
|
第二步,注册事件监听;在app/providers/eventserviceprovider.php中修改:
1
2
3
4
5
6
|
protected $listen = [
......
'illuminate\auth\events\login' => [
'app\listeners\userlogin' ,
],
];
|
文件app/listeners/userlogin.php粗糙地实现了一下:
1
2
3
4
5
6
7
|
class userlogin {
public function __construct() {}
public function handle(login $event ){
\log::info( 'do userlogin listener: i was login' );
}
}
|
第三步,触发事件,发送广播;有好几种触发广播方式:
直接事件触发
1
|
event( new illuminate\auth\events\login( $user , true));
|
帮助函数broadcast,间接触发事件
1
|
broadcast( new illuminate\auth\events\login( $user , true));
|
广播管理类,间接触发事件,直接广播
1
2
|
$manager = app(illuminate\broadcasting\broadcastmanager:: class );
$manager ->event( new illuminate\auth\events\login( $user , true));
|
广播管理类,间接触发事件,放入队列
1
2
|
$manager = app(illuminate\broadcasting\broadcastmanager:: class );
$manager ->queue( new illuminate\auth\events\login( $user , true));
|
pusher驱动
pusher是一个第三方服务,服务器发送广播时,会向pusher发送请求,再通过pusher与浏览器或移动端保持的长连接进行数据交互;
配置
通过pusher官网注册用户信息,获取属于自已的一套密钥信息,修改.env的配置文件;
1
2
3
4
|
broadcast_driver=pusher
pusher_app_id=xxxxxxxxxxxxxxxxxxxxxx
pusher_app_key=xxxxxxxxxxxxxxxxxxxxxx
pusher_app_secret=xxxxxxxxxxxxxxxxxxxxxx
|
准备工作
事件监听
后台的事件监听还是采用"日志驱动"部分的登录例子;
前端
前端页面引入以下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<script src= "https://js.pusher.com/4.1/pusher.min.js" ></script>
<script>
// 打开 pusher 的调试日志
pusher.logtoconsole = true;
// 定义 pusher 变量
var pusher = new pusher( 'pusher_app_key的值' , {
cluster: 'ap1' ,
encrypted: true
});
// 定义频道,绑定事件
var channel = pusher.subscribe( 'private-first-channel' );
channel.bind( 'login' , function (data) {
alert(data);
});
</script>
|
如果订阅的是公共频道,则不会向服务器端请求权限检查;如果是私有频道(频道名是以private-开头)或存在频道(频道名是以presence-开头),则会发出权限检查请求;对应的后端需要定义私有频道和存在频道的权限;
频道权限定义
频道的权限定义是在routes/channels.php里;此处笔者为first-channel频道定义权限回调函数:
1
2
3
|
broadcast::channel( 'first-channel' , function ( $user ) {
return (int) $user ->id === 1;
});
|
有读者会疑问,前端页面订阅的频道不是private-first-channel吗?怎么后端只定义first-channel频道的权限呢?那是因为,后端定义的频道假设是a,那么在pusher及浏览器端或移动端传递的私有频道名为private-a,存在频道则会是presence-a;
广播
直接广播
1
2
3
4
|
$manager = app(illuminate\broadcasting\broadcastmanager:: class );
$driver = $manager ->connection();
// socket 参数是广播私有频道时排除的 socket, 每个浏览器端或者移动端在建立 websocket 时都会被分配一个 socket_id
$driver ->broadcast([ 'private-first-channel' ], 'login' , [ 'user' => [ 'name' => 'hello' ], 'socket' => '5395.4377611' ]);
|
间接广播
参考“日志驱动”提及的间接广播方式;
如果要发送排我广播(也就是除了当前请求的这个客户端不收到广播消息),则需要以下条件:
- 事件使用illuminate\broadcasting\interactswithsockets trait;
- 前端发送过来的请求头部要携带x-socket-id信息;
- 事件触发执行broadcast(new illuminate\auth\events\login($user, true))->toothers();
redis驱动
配置
.env文件修改或添加一行:broadcast_driver=redis
;
广播
原理是同样在后端部署一个socket.io服务器,laravel框架会发布消息到socket.io服务器上,由socket.io服务器同浏览器端或者移动端保持长连接;
这部分笔者尚未demo,网上入门资料还是挺多的,知道原理,这部分动作上手就容易多了;
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。
附录
同类型的文章可参考以下,加深了解:
原文链接:https://segmentfault.com/a/1190000010759743