laravel-websockets 实现“低配版”广播系统

前言

网上找了好几个教程都没成功,然后死磕一个教程不断研究最终成功了。然后就写了这篇教程,希望能帮到跟我一样笨的人。另外希望不要误导到读者。希望读者最好不要过于信任我的这个教程。我其实是稀里糊涂地成功的,我的这个教程可能也有坑。还有一点是我觉得我研究的过程好像收获挺大的,但是收获的某些东西感觉没法用语言表达出来,如果时间充裕的话建议自己研究。

教程的开头我先大致介绍一下我是怎么搞出这个教程介绍的方法的。我建议看教程的人重视一下这部分,因为我怀疑 Laravel 或者相关的库一更新可能又会出现不兼容或者错乱的情况,然后就又有问题了。到时候可能就需要读者自行研究了。

为什么说是大致介绍呢,因为很多地方我感觉都是我瞎猫碰死耗子蒙出来的。另外可能需要一些无法言说的经验吧。

尽量缩小实验的对象的规模,找步骤少的教程

刚开始我是照着官方文档中文版做的,后来发现这个实在是太复杂了,可能错一步就会失败。而且有的时候连错误提示也没有,就算有错误提示不是搜不到就是有太多回答完全不一样的问题。如果尽量缩小规模的话,应该就能尽量少踩点坑了。

将任务分解得可以获得子任务成功的反馈

刚开始我是一步一步跟着做,然后最后看是否成功,后来发现这种方法太低效了。然后我发现某些子步骤是可以通过一些方法判断是否成功的,比如 laravel-websockets 安装成功之后能打开那个 dashboard。就是 /laravel-websockets 。另外还有发送广播的代码如果成功了的话可以在前面说的那个 dashboard 里看到效果。最后就是全部成功就能在浏览器里看到效果了。所以后来我如果当前阶段没有成功就不会继续做下去了,继续研究本阶段哪里错了。

多打 Log

我是通过打 Log 发现客户端的 Echo 根本没有初始化成功的,因为少个参数。之前好像也有个错误提示,但是我好像没看懂。通过在初始化 Echo 的前后分别输出两条不一样的 Log,我发现只有前一条执行了,后一条根本没执行,所以得出了程序遇到错误就停止执行了的结论。

对被实验的对象尽量熟悉起来

比如我没搜索到某条报错的相关信息。但是后来发现里面的某个词在配置里出现过,改了一下那个配置就好了。就是这个:“Uncaught Options object must provide a cluster”。不过后来我在网上发现个跟我一样的方法,没准我之前看过那个方法,可能是因为楼主说没用所以我就没试。

多综合各方信息,特别是那些成功的

虽然不一定能拿来就用,甚至可能会产生误导,但是我相信信息多一些还是更有助于解决问题的。比如我就在哔哩哔哩上搜过“laravel 广播”看过几个视频。还搜索了一些非官方文档的教程。

如果搜错误提示没有用的东西或者搜索结果太多就看看代码

不过我感觉这条有用的概率不大,实在没招了再用吧。我是通过这个方法发现我在取消注释代码的时候少取消注释了一行,然后出现了很奇怪的错误提示。

就算成功了也不要高兴得太早,多练习几遍

步骤越多越容易出问题,这个广播系统的步骤是真多。多练习也能多熟悉一点。

尽量选择更新的教程

我一般在搜索引擎里加个一年内的条件。

面向搜索引擎编程

感觉这次大概有一半以上的问题都是通过搜索引擎解决的吧,完全自己解决的部分好像很少。

本体

我这个教程某些方面比较啰嗦,是从创建项目开始的,另外还提到了配置数据库。水平比较高的读者可以忽略一些内容。至于高端的读者应该用不着看我的这种东西。不过我对命令的介绍基本没有,有需求建议去看下面的英文文章。

我这个是公共频道的。还有队列用的是默认的 sync,据说只能用于开发环境。总之我这个教程应该是挺残废的,但是跑通了应该就可以以此为起点根据官方文档实验新的配置和添加新的功能了。

我的这个教程主要参考自这篇文章:How to use Laravel WebSockets

补充

文章创建两天后发现忘了说安装 Vite 了。下面是安装 Vite 的教程:
Laravel Vite 编译 Assets
有点想在虚拟机里来一遍,但是感觉太麻烦了。

创建项目

在 Apache24\htdocs 或者类似的地方运行下面的命令:

composer create-project laravel/laravel bc

在项目路径中运行以下命令:

php artisan serve

注意运行完上面的命令当前命令行窗口一般就不能运行命令了,需要重启一个命令行窗口。想要在继续在当前命令行窗口运行命令除非配合后台运行的命令。

配置数据库信息

在配置数据库之前需要创建一个数据库,我用的是 test。不过就算不创建在 migrate 的时候也会提示创建。这个差点就忘了,因为之前一直没有删除这个数据库。

.env

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=test
DB_USERNAME=root
DB_PASSWORD=1234

注意要填你的数据库的实际的信息,别照抄我的配置。

安装服务器端包 beyondcode/laravel-websockets

在项目路径中运行以下命令:

composer require beyondcode/laravel-websockets
php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="migrations"
php artisan migrate
php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="config"

安装 pusher

在项目路径中运行以下命令:

composer require pusher/pusher-php-server

注意这条我跟我参考的那篇文章不一样,我这个安装的应该是最新版的。原文好像指定版本了。

配置 Laravel WebSockets

.env

BROADCAST_DRIVER=pusher

PUSHER_APP_ID=12345
PUSHER_APP_KEY=ABCDEFG
PUSHER_APP_SECRET=HIJKLMNOP
PUSHER_HOST=127.0.0.1
PUSHER_PORT=6001
PUSHER_SCHEME=http
PUSHER_APP_CLUSTER=mt1

注意这里跟我参考的那篇英文文章也不一样,我强迫症,感觉改 .env 更优雅一些。毕竟其他地方都会优先读 .env。感觉 .env 更像是函数,一个地方改动了不用修改所有调用的地方。感觉前一句有点问题,大概就是那个意思吧。

再注意一下第二条到第四条的值是随便填的。

运行 Laravel WebSockets 服务器

在项目路径中运行以下命令:

php artisan websockets:serve

这个也是运行之后当前命令行窗口就不能输入命令了。

之后在浏览器地址栏输入 127.0.0.1:8000/laravel-websockets 就能看前面的操作是否成功了。如果你不是通过“php artisan serve”运行的服务器的话可能端口会不一样。点击那个 Connect 按钮如果在 Events 下面出现一些东西应该就是阶段性成功了。注意这个网页在没那个啥的情况下打开是非常慢的,至少在我这里很慢。因为里面有个 js 库的下载速度很慢。注意下面的改 blade 模板的行为是可选的!另外我不知道下面的那个 cdn 有没有问题,毕竟好像不是大厂的 cdn。如果你嫌慢又不想那个啥的话可以将 vendor\beyondcode\laravel-websockets\resources\views\dashboard.blade.php 中的

<script  src="https://cdn.plot.ly/plotly-latest.min.js"></script>

换成

<script  src="https://cdn.bootcdn.net/ajax/libs/plotly.js/2.17.0/plotly.min.js"></script>

我是通过用 VS Code 搜索功能直接搜索 cdn.plot.ly/plotly-latest.min.js 搜出来这个文件的。另外是在火狐的开发者工具的网络中发现这个 js 库加载速度慢的。另外这种直接改这种地方的文件应该是不太优雅。

创建事件

在项目路径中运行以下命令:

php artisan make:event NewTrade

app\Events\NewTrade.php

<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class NewTrade implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $trade;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct($trade)
    {
        $this->trade = $trade;
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new Channel('trades');
    }
}

在项目路径中运行以下命令:

php artisan tinker

运行这条命令后会启动 Laravel 的交互式解释器,我理解就是输入一些语句可以直接执行。另外还有一些其他的实用的命令。这个也是运行之后当前命令行窗口就不能输入正常的系统命令了,但是这个命令行窗口之后要输入 php 语句。顺便说一下,VS Code 里的终端在 tinker 里没法 Ctrl + V,但是右键是粘贴的功能。

然后在上面的执行过 php artisan tinker 的那个命令行窗口运行以下命令:

event (new \App\Events\NewTrade('test'))

之后就能在上面提到的那个 127.0.0.1:8000/laravel-websockets 页面看到发出的消息了。能看到的话就说明阶段性成功了。

安装客户端包 laravel-echo

在项目路径中运行以下命令:

npm install
npm install --save-dev laravel-echo pusher-js

resources\js\bootstrap.js

import Echo from 'laravel-echo';

import Pusher from 'pusher-js';
window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: import.meta.env.VITE_PUSHER_APP_KEY,
    wsHost: import.meta.env.VITE_PUSHER_HOST ? import.meta.env.VITE_PUSHER_HOST : `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
    wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80,
    wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443,
    forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
    enabledTransports: ['ws', 'wss'],
    cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
});

注意这里也跟我参考的那篇英文文章不一样。我只是取消注释了那个文件中的那些东西,并在结尾添加了一行“cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,”。

在项目路径中运行以下命令:

npm run dev

这个也是运行之后当前命令行窗口就不能输入命令了。

添加客户端脚本

在文件
resources\views\welcome.blade.php
的 head 标签的结尾添加以下代码:

        @vite('resources/js/app.js')
        <script>
            window.onload = function(){
                window.Echo.channel('trades')
                .listen('NewTrade', (e) => {
                    console.log(e.trade);
                });
            };
        </script>
    </head>

注意这里也跟我参考的那篇英文文章不一样。改了两处,一个是导入 app.js 的方法换了。另外套了一层 window.onload。

然后在浏览器的地址栏输入 127.0.0.1:8000/ 启动开发者工具并切换到控制台标签页。然后再在前面运行过 php artisan tinker 的那个命令行窗口中执行以下命令:

event (new \App\Events\NewTrade('test'))

最后切换到前面提到的开发者工具中的控制台标签页,应该能看到一条“test”消息。能看到就说明最终成功了。

结语

我只是个菜狗,不要问我太复杂的问题。我从开始搞这个广播系统到最终成功好像用了两三天的时间,就凭这个时间你应该就能体会到我有多菜了。

最后因为我是菜狗,所以可能会有一些理解上的错误,欢迎指出来。不过按照我的这个教程做基本上应该是会成功的。我做完这个教程自己照着又做了两遍,没问题。不过也可能会因为我没注意到一些东西,或者读者的环境跟我的不一样导致读者不成功。所以我也不敢保证。感觉早晚会失效,失效了如果我没更新的话谁看到了就回复一下提醒一下别人吧。

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 3

太棒了 :+1:,乐于分享,你这个就是最新的教程。

1年前 评论

要不要试试看soketi 、我最近想把laravel-websockets改成soketi

1年前 评论
goStruct

这个跟swoole和wokerman相比,我更愿意用后两者。

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!