基于 Pusher 驱动的 Laravel 事件广播(上)

2022-01-10 09:16:16 浏览数 (1)

说明:本文主要来源于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 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:

代码语言:javascript复制
    curl -sS https://getcomposer.org/installer | php
    mv composer.phar /usr/local/bin/composer

新建一个空文件夹,在文件夹下,再使用composer安装Laravel项目:

代码语言:javascript复制
composer create-project laravel/laravel mylaravelapp --prefer-dist

2.3 配置Pusher认证密钥

在项目根目录的.env文件中加入密钥,把刚刚获得的密钥换成你自己的就行,.env文件是Laravel项目配置文件:

代码语言:javascript复制
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,安装:

代码语言:javascript复制
composer require vinkla/pusher

安装完后注册下服务,service provider主要就是把刚刚下载的service(包)在Laravel容器中注册下,每一个service(包)都有对应的一个service privider:

代码语言:javascript复制
VinklaPusherPusherServiceProvider::class,

并同时把这个包的配置文件复制到config文件夹下,config文件夹下多了一个pusher.php文件:

代码语言:javascript复制
php artisan vendor:publish

在config/pusher.php文件中更新下配置文件:

代码语言:javascript复制
'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[] 数组中。

代码语言:javascript复制
'Pusher' => VinklaPusherFacadesPusher::class

配置并安装好这个包后就来检测下能不能使用:

代码语言:javascript复制
get('/bridge', function() {
    $pusher = IlluminateSupportFacadesApp::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的密钥:

代码语言:javascript复制
'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:

代码语言:javascript复制
protected $listen = [
        'AppEventsPusherEvent' => [
            'AppListenersPusherEventListener',
        ],
    ];

然后在项目根目录生成事件和对应的监听器:

代码语言:javascript复制
php artisan event:generate

Laravel中事件如果需要广播,必须实现IlluminateContractsBroadcastingShouldBroadcast接口,并且事件中public属性都会被序列化作被广播的数据,即public属性数据会被发送。同时,还需要在broadcastOn()函数中写入任意字符的广播频道:

代码语言:javascript复制
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'];
    }
}

好,然后触发这个事件,为了简单,就直接在路由中触发:

代码语言:javascript复制
Route::get('/broadcast', function () {
    event(new AppEventsPusherEvent('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属性被广播:

代码语言:javascript复制
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 AppEventsPusherEvent('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模块进行调试:

代码语言:javascript复制
use IlluminateSupportFacadesApp;
use IlluminateSupportFacadesLog;

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文件再查看:

代码语言:javascript复制
[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/css?family=Lato:100 注销掉免得每次加载有些慢。在文件中写入代码:

代码语言:javascript复制
<script src="//js.pusher.com/3.0/pusher.min.js"></script>
<script>
var pusher = new Pusher("{{env("PUSHER_KEY")}}")
var channel = pusher.subscribe('test-channel');
channel.bind('test-event', function(data) {
  console.log(data);
  console.log(data.text);
});
</script>

先加载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窗口打印信息:

It is working!

可以多次刷新路由,在两个标签页面间切换看看打印的数据。A页面触发事件B页面能接收到数据;B页面触发事件A页面接收到数据。

2.9 调试Pusher JavaScript客户端

可以使用Pusher Debug Console控制面板查看触发情况,当然可以在客户端打印调试信息:

代码语言:javascript复制
<script>
            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。

0 人点赞