手把手教你用Laravel-echo-server 建立广播系统

浏览量:321

开始之前

  • Laravel并没有官方的Socket.IO 服务器,所以我们使用Laravel-echo-server 这个第三方库,只要正确配置,无缝接入Laravel
  • 需要会使用Laravel 的事件的写法
  • 确保config/broadcasting.php 中default 不为null

原理简述

Laravel 广播系统的原理其实很简单,客户端与Socket.io服务端(Laravel-echo-server) 建立连接,服务端监听驱动器事件,当驱动器产生事件时,服务端(Laravel-echo-server)监听到事件并向指定频道发送事件消息,客户端监听指定频道,收取事件消息。

建立连接

驱动器

本文使用Redis 作为驱动器, 请参考Laravel Redis 的配置项并保证正常使用。

服务端(发送广播)

Laravel-echo-server

安装

需要全局安装Laravel-echo-server。

npm install -g laravel-echo-server

初始化配置

使用包自带的init 命令可以快速初始化配置文件

laravel-echo-server init

首次使用可以一路回车,全使用默认配置,执行后路径下会生成 laravel-echo-server.json 文件,根据实际需要再修改配置信息。

{
  "authHost": "dash.dev.car.co.uk",
  "authEndpoint": "/broadcasting/auth",
  "clients": [
    {
      "appId": "",
      "key": ""
    }
  ],
  "database": "redis",
  "databaseConfig": {
    "redis": {
      "port": "6379"
    }
  },
  "devMode": false,
  "host": null,
  "port": "6001",
  "protocol": "http",
  "socketio": {},
  "secureOptions": 67108864,
  "sslCertPath": "",
  "sslKeyPath": "",
  "sslCertChainPath": "",
  "sslPassphrase": "",
  "subscribers": {
    "http": true,
    "redis": true
  },
  "apiOriginAllow": {
    "allowCors": false,
    "allowOrigin": "",
    "allowMethods": "",
    "allowHeaders": ""
  }
}

注意:

  • appId 是使用http 请求来触发广播的,如果只需要在Laravel 中使用Redis 触发广播,可以忽略此项配置。
  • 开发时建议devMode 设为true, 可以直观的看到连接及server 运行情况。
  • 注意驱动器的配置,给驱动器配置正确的地址及端口。
  • 跨域请求对cookies 有限制,注意合适的跨域配置

启动

laravel-echo-server start

看到”Server ready!“ 证明server 已经启动成功了。

Laravel

触发广播事件

广播依赖于事件系统,这样设计是有原因的。
事件系统可以很好的解耦某个逻辑的不同响应,比如用户注册后可以短信、邮件等多种方式通知用户注册成功,并执行其他操作,使用一个事件及多个监听器就可以很好的解耦业务逻辑。

定义广播事件

将事件实现 Illuminate\Contracts\Broadcasting\ShouldBroadcast

use Illuminate\Broadcasting\Channel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

class BroadcastDemo implements ShouldBroadcast
{
    public function broadcastOn()
    {
        // need return a channel or channels
        return new Channel('channel-demo');
    }
}

必须存在 broadcastOn方法,该方法返回一个频道或者频道数组,事件会被广播到这些频道。
正常触发事件就可以触发广播。

广播数据

Laravel 会默认将事件中public 属性自动序列化为广播数据,即允许客户端访问事件中的公有数据。
但是也可以使用broadcastWith 方法更细粒度的控制广播数据。

广播驱动

需要配置和laravel-echo-server 相同的驱动器,驱动器来实现发布-订阅模式,laravel 使用事件系统发布消息,laravel-echo-server订阅事件,做出回调(使用socket.io 推送消息),这里我们使用的是redis作为队列驱动程序,当laravel 触发推送到指定频道时,在redis-cli 中使用SUBSCRIBE 监听对应频道或所有频道也可以看到具体信息。

频道

依然拿现实中的广播系统做类比,公共频道就像广播电台,客户端只要能连接到指定频道就都可以收听,但很多信息是不能放在公开频道上的,所以需要授权以进入频道。

频道认证

当连接私有频道时,客户端向laravel-echo-server发起请求,laravel-echo-server 将此请求转发给Laravel 以判断是否应该授权。
Laravel 默认授权路由为:/broadcasting/auth,通常来说使用

Broadcast::routes();

就会注册授权路由,或者可以使用BroadcastManager 来更细粒化的控制。
在routes/channels.php 中使用Broadcast::channel 方法定义授权回调,方法返回Boolean 值,回调中当前用户被当做第一个参数,额外的通配符参数会被作为后续参数。
需要注意的是,由于通配符中也使用了「.」,所以参数中会只取第一个点前面的字符。实际使用中可以将「.」替换为其他字符来获取完整信息

仅广播给他人

现实中,如果边听收音机边给电台热线打电话,收音机中肯定也会出现电话对话声,离得近了甚至会产生回音。
网络中的广播系统自然也会有这种情况发生,但在网上是没法走开的,所以需要广播系统可以针对性的进行推送,避开触发此次广播的用户。
laravel 在每个请求中使用X-Socket-ID 来标识用户,客户端可以将X-Socket-ID 设为socketId,使用axios 时库会自动向header中添加,但使用其他请求库时可以在socket 连接建立后将X-Socket-ID配置如header,可以参考以下代码:

echoInstance.connector.socket.on('connect', () => {
  http.defaults.headers.common['X-Socket-Id'] = echoInstance.socketId();
});

当请求携带有X-Socket-ID时,调用broadcast函数时使用toOthers 方法,即可将指定连接从广播接收者中排除。

broadcast(new BroadcastDemo())->toOthers();

到目前为止,我们已经构建了一个可以适应大部分需求的广播系统的发送,接下来我们看看如何配置客户端。

客户端(接收广播)

建立连接

客户端需要使用 Socket.IO JavaScript库来建立文件,当启动laravel-echo-server 后,可以通过 server 地址及端口号获取Socket.IO 库,比如开发时通常使用http://localhost 与6001 端口,可以使用

http://localhost:6001/socket.io/socket.io.js

获取到Socket.IO 库。
如果需要手动在客户端添加Socket.IO 库,请注意socket.io.js 版本,目前只有2.x 版本可以正常使用。

接着,我们需要在合适的时机建立实例化Echo(示例代码使用localhost 与6001端口):

import Echo from "laravel-echo"

const EchoInstance = new Echo({
    broadcaster: 'socket.io',
    host: 'http://localhost:6001'
});

实例化Echo 时,客户端的echo 库会发送http 请求到server 端请求建立连接。

加入频道

建立连接后可以使用echoInstance的channel 方法加入指定频道,使用listen 监听频道上的指定事件:

echoInstance
      .channel('channelName')
      .listen('eventName', ()=>{
        //   callback
      })

需要退出频道时,使用leave 方法即可。

留下评论