基于 Redis 实现 Laravel 广播功能(中):引入 Laravel Echo 接收广播消息

2021-01-08 15:50:16 浏览数 (1)

启动 Laravel Echo Server

上篇教程我们完成了广播系统的后端配置和事件分发,并探究了底层源码的实现,最终落地的都是通过 Redis 发布命令发布消息。

接下来我们需要借助 Laravel Echo Server 搭建起 Websocket 服务器,这里面除了封装 Socket.io 服务端之外,还包含了订阅服务端广播频道的 Redis 客户端,用于接收服务端 Redis 发布的消息,再通过 Socket.io 广播给客户端。

如果是在本地搭建,按照 Laravel Echo Server 文档给出的安装和启动步骤操作即可,如果使用的是 Laradock,其内置了 laravel-echo-server 这个容器服务配置,使用 docker-compose up -d laravel-echo-server 启动即可,如果使用的是 Laravel Sail 作为本地开发环境,可以参考 Laradock 提供的 laravel-echo-server 编排配置引入它。

通过 Sail 编排 Laravel Echo Server

在项目根目录的 docker 目录下(我已经通过 sail artisan sail:publish 发布了 Sail 的容器编排文件,所有会有这个目录)新建一个 laravel-echo-server 子目录,然后把 laradock/laravel-echo-server 目录下的所有文件拷贝到这个子目录下:

修改 laravel-echo-server.json 配置如下:

代码语言:javascript复制
{
    "authHost": "redis.test",
    "authEndpoint": "/broadcasting/auth",
    "clients": [],
    "database": "redis",
    "databaseConfig": {
        "redis": {
            "port": "6379",
            "host": "redis"
        }
    },
    "devMode": true,
    "host": null,
    "port": "6001",
    "protocol": "http",
    "socketio": {},
    "sslCertPath": "",
    "sslKeyPath": "",
    "subscribers": {
        "http": true,
        "redis": true
    },
    "apiOriginAllow": {
        "allowCors": true,
        "allowOrigin": "redis.test",
        "allowMethods": "GET, POST",
        "allowHeaders": "Origin, Content-Type, X-Auth-Token, X-Requested-With, Accept, Authorization, X-CSRF-TOKEN, X-Socket-Id"
    }
}

在项目根目录下 docker-compose.ymlservices 中新增一个 laravel-echo-server 服务编排配置:

代码语言:javascript复制
services:
    ...
    laravel-echo-server:
        build:
            context: ./docker/laravel-echo-server
            dockerfile: Dockerfile
            args:
                - CHANGE_SOURCE=${CHANGE_SOURCE}
        volumes:
            - ./docker/laravel-echo-server/laravel-echo-server.json:/app/laravel-echo-server.json:ro
        ports:
            - "${LARAVEL_ECHO_SERVER_PORT}:6001"
        depends_on:
            - redis
        networks:
            - sail

.env 中新增两个配置项:

代码语言:javascript复制
CHANGE_SOURCE=true
LARAVEL_ECHO_SERVER_PORT=6001

然后就可以通过如下命令启动 Laravel Echo Server 容器服务了:

代码语言:javascript复制
sail up -d

初次构建会先拉取 laravel-echo-server 的容器镜像。启动完成后,就可以通过 sail ps 命令查看它是否启动成功:

或者通过查看 laravel-echo-server 日志也可以确认它是否启动成功:

Laravel Echo 客户端

启动好 Laravel Echo Server 后,接下来,我们来安装配置 Laravel 官方提供的广播客户端前端库 Laravel Echo,它既支持 Pusher,也支持 Socket.io,这里我们肯定需要通过 Socket.io 客户端进行通信了。

由于我们上篇教程已经在项目中安装过 socket.io-client,所以只需要单独安装 laravel-echo 即可,不过需要把 package.json 中已安装的 socket.io-client 版本调整为与 laravel-echo-server 中的 socket.io 版本一致,否则很可能导致 Websocket 连接建立失败(学院君就遇到了这个问题,折腾了半天,网上也没啥靠谱的答案,最后灵感突发,猜测是不是客户端与服务端版本不一致引起的,最后验证了下还真是,目前这个版本号是 2.3.0,将 socket.io-client 版本号调整为 ^2.3.0 即可):

代码语言:javascript复制
npm install --save laravel-echo

然后在 resources/js/bootstrap.js 中取消 Laravel Echo 相关代码前面的注释,并将 Pusher 客户端实现调整为 Socket.io 客户端:

代码语言:javascript复制
import Echo from 'laravel-echo';

window.io = require('socket.io-client');

window.Echo = new Echo({
    broadcaster: 'socket.io',
    host: window.location.hostname   ':6001'
});

window.Echo.channel('laravel_database_test-channel').listen('UserSignedUp', event => {
    console.log(event.user);
});

运行 sail npm run dev 编译前端代码让上述修改生效。

至此,我们就将前面基于 Redis Socket.io 原生代码实现的事件广播功能重构为了基于 Laravel 广播组件 Laravel Echo Server Laravel Echo 实现的完整广播系统了,这样一来,我们就可以使用 Laravel 广播系统提供的所有功能了,包括事件广播的推送和接收、私有频道、存在频道等。

不过在此之前,我们还是验证下这个广播系统是否可以正常工作。

验证 Laravel 事件广播消息推送

在访问 /broadcast 路由前,还需要在 resources/views/websocket.blade.php<head> 标签中添加获取 CSRF 令牌的代码以便被 Laravel Echo 读取:

代码语言:javascript复制
<meta name="csrf-token" content="{{ csrf_token() }}">

在浏览器中访问 http://redis.test/broadcast,此时服务端还没有推送事件广播消息,但是可以在 laravel-echo-server 日志中看到 Websocket 客户端信息,joined 表示客户端与服务端建立连接,left 表示客户端断开连接,之所以出现下面这个 joined-left-joined 日志,是因为我刷新过 /broadcast 页面:

在浏览器中也可以在开发者工具中看到熟悉 Socket.io Websocket 连接成功消息流:

接下来,我们运行如下 Artisan 命令分发事件广播:

代码语言:javascript复制
sail artisan redis:publish

然后启动队列处理器进程处理 broadcast 队列消息(这一步也不能漏了哈,因为 Laravel 默认是基于消息队列处理广播消息的):

代码语言:javascript复制
sail artisan queue:work --queue=broadcast

这个时候,查看 laravel-echo-server 的日志,就可以看到服务端发布的事件消息已经被 Laravel Echo Server 中的 Redis 接收处理了:

底层原理和我们通过 Redis Socket.io 原生代码实现广播功能是一样的,基于 Redis 订阅功能实现,感兴趣的同学可以去看下 Laravel Echo Server 实现源码。

在浏览器页面开发者工具的 Console 中,也可以看到客户端接已经收到这个事件消息并打印出用户信息来了:

至此,从 Laravel 服务端到 Laravel Echo Server 到 Laravel Echo 客户端的广播链路就已经打通了。

本系列教程首发在学院君网站(xueyuanjun.com),你可以点击页面左下角阅读原文链接查看最新更新的教程。

0 人点赞