说明:本文主要来源于Building Real-Time Laravel Apps with Pusher。
本文主要介绍使用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 Streams
Activity 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_ID
PUSHER_KEY=YOUR_APP_KEY
PUSHER_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的话会报错,所以不用配置。可以使用IlluminateSupportFacadesApp::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...路由,正确返回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中查看触发结果:
其中'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 Pusher Bridge方式。
有时间可以看下Laravel Debug Bar,就是一个供Laravel调试的包,地址:Laravel Debug Bar,这大牛还写了个Laravel IDE Helper也非常好用:Laravel IDE Helper。。强烈建议把这两个包安装到你的项目中,每一个新Laravel项目都可以安装下。。
2.8 使用Pusher JavaScript包
好,既然服务端可以工作正常了,那现在开始研究下客户端来接收事件触发时服务端发送来的数据。可以新建一个view,或者直接使用已有的welcome.blade.php这个view,但先把这个文件的 https://fonts.googleapis.com/... 注销掉免得每次加载有些慢。在文件中写入代码:
先加载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发生什么:
然后新开一个标签页再输入http://laravelpusher.app:8888/bridge
路由看看console窗口打印信息:
可以多次刷新路由,在两个标签页面间切换看看打印的数据。A页面触发事件B页面能接收到数据;B页面触发事件A页面接收到数据。
2.9 调试Pusher JavaScript客户端
可以使用Pusher Debug Console控制面板查看触发情况,当然可以在客户端打印调试信息: