本文主要介绍使用pusher包来开发带有实时通信功能的laravel app,整个教程只需要两个小时就能顺利走一遍。同时,作者会将开发过程中的一些截图和代码黏上去,提高阅读效率。
1. 教程相关 本教程所需条件:
已经安装composer
基本了解php
基本了解laravel
基本了解jquery
有一个github账户
备注:laravel是一个流行的php全栈框架,composer是一个php包管理器,jquery是一个操作dom树的javascript框架。如果有不了解的,可以在看教程前花半个小时谷歌下这些基本内容比较好。被墙了咋办,去github上搜lantern,你懂得。
1.1 pusher是什么?
pusher是客户端和服务器之间的实时中间层,通过websocket或http来和客户端实现持久链接,这样服务端可以实时向客户端发送数据。总之,就是一个实现持久链接的包。
1.2 pusher用途
(一) 通知(notification)/信号(signal)
通知是最简单的示例,也最经常用到。信号也可看作是通知的一种展现形式,只不过信号没有ui而已。
(二) activity streamsactivity streams(feeds)是社交网络的核心。如微信朋友圈的点赞和评论,a可以实时看到b的点赞,b可以实时看到a的评论。
(三) 实时数据可视化如在dashboard数据面板中实时显示投票数,或者实时显示天气情况等等。
(四) 聊天
聊天信息的实时显示,如微信。
等等。具体可看 pusher use cases
2. pusher主要内容 这部分内容主要包括注册pusher账号,在php程序中注册pusher的id和密钥,把pusher的php包和javascript包集成进laravel,以及如何调试pusher程序。
2.1 注册pusher账号
注册pusher账号:可以在这里注册: pusher 注册 ,注册账号主要是为了获得appid,secret和key这三个认证密钥,同时注册后进入个人页面后,可以使用pusher的pusher debug console来查看接口调用情况。可以用github账号来注册登录的。
注册成功后进入个人后台面板,可以新建个应用程序名称,会有该新建程序的密钥,同时右边第二个tab还有个debug console,用来调试查看接口调用情况,等会会用到:
2.2 laravel程序安装 先全局安装composer:
curl -ss https://getcomposer.org/installer | php mv composer.phar /usr/local/bin/composer
新建一个空文件夹,在文件夹下,再使用composer安装laravel项目:
composer create-project laravel/laravel mylaravelapp --prefer-dist
2.3 配置pusher认证密钥 在项目根目录的.env文件中加入密钥,把刚刚获得的密钥换成你自己的就行,.env文件是laravel项目配置文件:
pusher_app_id=your_app_idpusher_key=your_app_keypusher_secret=your_app_secret
然后,把pusher集成到laravel的后端,有两种方式:使用laravel pusher bridge;使用laravel event broadcaster。
2.4 laravel pusher bridge 在 php包资源库 中查找 pusher ,安装:
composer require vinkla/pusher
安装完后注册下服务,service provider主要就是把刚刚下载的service(包)在laravel容器中注册下,每一个service(包)都有对应的一个service privider:
vinkla\pusher\pusherserviceprovider::class,
并同时把这个包的配置文件复制到config文件夹下,config文件夹下多了一个pusher.php文件:
php artisan vendor:publish
在config/pusher.php文件中更新下配置文件:
'connections' => [ 'main' => [ 'auth_key' => env('pusher_key'), 'secret' => env('pusher_secret'), 'app_id' => env('pusher_app_id'), 'options' => [], 'host' => null, 'port' => null, 'timeout' => null, ],
这里有一个安装bug:如果同时也在config/app.php中配置了facade的话会报错,所以不用配置。可以使用\illuminate\support\facades\app::make('pusher')来从laravel的container容器中取出pusher服务。一般可以用facade从容器中取出服务,但这个包不好使,有bug。 下面这句不用加在config/app.php中aliases[]数组中。
'pusher' => vinkla\pusher\facades\pusher::class
配置并安装好这个包后就来检测下能不能使用:
get('/bridge', function() { $pusher = \illuminate\support\facades\app::make('pusher'); $pusher->trigger( 'test-channel', 'test-event', ['text' => 'i love china!!!'] ); return 'this is a laravel pusher bridge test!';});
作者在mamp pro环境中,apache端口是8888,在浏览器中输入 http://laravelpusher.app:8888/bridge 路由,正确返回 this is a laravel pusher bridge test! ,说明pusher已经触发。可以在pusher debug console后台查看是否触发:
的确, it is working! 很简单是不是。
2.5 laravel event broadcaster
laravel5.1以后提供了event broadcaster功能,配置文件是config/broadcasting.php,并且默认驱动是pusher: 'default' => env('broadcast_driver', 'pusher') ,如果不是可以在.env文件中添加broadcast_driver=pusher。总之,不需要修改啥配置了。broadcasting.php中也是要读取pusher的密钥:
'connections' => [ 'pusher' => [ 'driver' => 'pusher', 'key' => env('pusher_key'), 'secret' => env('pusher_secret'), 'app_id' => env('pusher_app_id'), 'options' => [ // ], ], ...
既然事件广播,那就需要生成事件和对应的监听器,在app/providers/eventserviceprovider.php中写入任何一个事件名称如someevent,和对应的监听器如eventlistener:
protected $listen = [ 'app\events\pusherevent' => [ 'app\listeners\pushereventlistener', ], ];
然后在项目根目录生成事件和对应的监听器:
php artisan event:generate
laravel中事件如果需要广播,必须实现illuminatecontractsbroadcastingshouldbroadcast接口,并且事件中public属性都会被序列化作被广播的数据,即public属性数据会被发送。同时,还需要在broadcaston()函数中写入任意字符的广播频道:
class pusherevent extends event implements shouldbroadcast{ use serializesmodels; public $text, $id; /** * create a new event instance. * * @return void */ public function __construct($text, $id) { $this->text = $text; $this->id = $id; } /** * get the channels the event should be broadcast on. * * @return array */ public function broadcaston() { return ['laravel-broadcast-channel']; }}
好,然后触发这个事件,为了简单,就直接在路由中触发:
route::get('/broadcast', function () { event(new \app\events\pusherevent('great wall is great ', '1')); return 'this is a laravel broadcaster test!';});
在pusher debug console中查看触发结果:
it is working! 。
其中'laravel-broadcast-channel'就是channel属性,appeventspusherevent是event属性,pusherevent的public属性是被广播的数据,为了检验只有public属性被广播:
class pusherevent extends event implements shouldbroadcast{ use serializesmodels; public $text, $id; private $content; protected $title; /** * create a new event instance. * * @return void */ public function __construct($text, $id, $content, $title) { $this->text = $text; $this->id = $id; $this->content = $content; $this->title = $title; } /** * get the channels the event should be broadcast on. * * @return array */ public function broadcaston() { return ['laravel-broadcast-channel']; }}//routes.php中route::get('/broadcast', function () { event(new \app\events\pusherevent('this is a public attribute', '2', 'this is a private attribute', 'this is a protected attribute')); return 'this is a laravel broadcaster test, and private/protected attribute is not fired!';});
重新触发查看pusher debug console,的确只有public属性数据被广播:
2.6 laravel pusher bridge vs laravel event broadcaster
使用laravel pusher bridge可以不必被event broadcaster的一些规则束缚,并且可以通过pusher实例来获取pusher提供的其他服务如验证频道订阅,查询程序状态等等。不过使用laravel event broadcaster可以实现模块解耦,当有其他的更好的push包时可以快速切换别的服务。可以选择适合的方法。
2.7 调试pusher服务端集成包 本小节主要涵盖使用laravel pusher bridge方法作为事件广播的调试。使用pusher php包的log模块并结合laravel的log模块进行调试:
use illuminate\support\facades\app;use illuminate\support\facades\log;class laravelloggerproxy{ public function log($msg) { log::info($msg); }}class appserviceprovider extends serviceprovider{ /** * bootstrap any application services. * * @return void */ public function boot() { $pusher = app::make('pusher'); $pusher->set_logger(); } ...
作者在个人环境中,输入 http://laravelpusher.app:8888/bridge ,在storage/logs/laravel.log中会出现类似如下的调试信息,可以先清空下laravel.log文件再查看:
[2016-04-25 02:25:10] local.info: pusher: ->trigger received string channel test-channel. converting to array. [2016-04-25 02:25:10] local.info: pusher: curl_init( http://api.pusherapp.com:80/apps/200664/events?auth_key=ae93fbeaff568a9223d3&auth_signature=ff8ce0b76038aea6613b4849ddda1b2bd0b14976738e8751264bf8f3cab3bc41&auth_timestamp=1461551110&auth_version=1.0&body_md5=bde7265f1c9da80ce0a3e0bde5886b5a ) [2016-04-25 02:25:10] local.info: pusher: trigger post: {name:test-event,data:{\text\:\i love china!!!\},channels:[test-channel]} [2016-04-25 02:25:11] local.info: pusher: exec_curl response: array( [body] => {} [status] => 200)
调试信息可看到,使用pusher是往这个接口 http://api.pusherapp.com:80/apps/200664/events?auth_key=&auth_signature=&auth_timestamp=&auth_version=&body_md5= 发post数据,发的数据主要是3个:频道channels(如:test-channel),事件event(如:test-event)和数据data(如:i love china)。最后返回响应,状态200,就表示发送成功了。如果输入路由 http://laravelpusher.app:8888/broadcast 则laravel.log中不打印调试消息。
有时间可以看下laravel debug bar,就是一个供laravel调试的包,地址: laravel debug bar ,这大牛还写了个laravel ide helper也非常好用: laravel ide helper 。。强烈建议把这两个包安装到你的项目中,每一个新laravel项目都可以安装下。。
2.8 使用pusher javascript包 好,既然服务端可以工作正常了,那现在开始研究下客户端来接收事件触发时服务端发送来的数据。
可以新建一个view,或者直接使用已有的welcome.blade.php这个view,但先把这个文件的注销掉免得每次加载有些慢。在文件中写入代码:
先加载pusher的js包,再利用pusher对象去订阅频道,再用频道绑定触发事件,闭包返回接收到的数据。这里订阅laravel pusher bridge里写的test-channel频道,绑定test-event事件,打印text属性的数据,我们知道上文中我们写入了数据为['text' => 'i love china!!!'],那客户端打印的数据应该是'i love china!!!',看看是不是。在路由中输入 http://laravelpusher.app:8888/bridge 看看pusher debug console发生什么:
然后新开一个标签页再输入路由看看console窗口打印信息:
it is working! 可以多次刷新路由,在两个标签页面间切换看看打印的数据。a页面触发事件b页面能接收到数据;b页面触发事件a页面接收到数据。
2.9 调试pusher javascript客户端 可以使用pusher debug console控制面板查看触发情况,当然可以在客户端打印调试信息:
pusher.log = function(msg) { console.log(msg); }; var pusher = new pusher({{env(pusher_key)}}); var channel = pusher.subscribe('test-channel'); ...
看打印信息知道,开始是connecting,然后连接成功connected,然后频道订阅成功subscription_succeeded,最后事件也被接收且数据也发送成功event recd。
总结:上部分包括pusher服务账号注册、laravel实时app安装、pusher服务端的集成和调试和pusher客户端的集成和调试。下部分将主要以示例来说明,包括:real-time notification, activity stream, chat。
