Laravel10,Laravel广播,Laravel-echo使用

最近又想用下 Laravel 的广播,结果发现和之前的不一样了,乘着项目上线遇到的一些坑,做一下使用流程

用到得东西:

  • predis
  • socket.io-client@2.3.0
  • laravel-echo-server
  • laravel-echo
  • laravel-10

第一步:用到的东西都安装一下

在项目根目录执行下面

 $> npm install socket.io-client@2.3.0 #版本一定要对!
 $> npm install laravel-echo
 $> npm install -g laravel-echo-server
 $> laravel-echo-server init
 ? Do you want to run this server in development mode? Yes # 生产环境为 No
 ? Which port would you like to serve from? 6001 #服务端口
 ? Which database would you like to use to store presence  channel members? redis #redis
 ? Enter the host of your Laravel authentication server. http://localhost #host
 ? Will you be serving on http or https? http # http
 ? Do you want to generate a client ID/Key for HTTP API? No #No
 ? Do you want to setup cross domain access to the API? Yes #我这边项目是不同的域名所以需要进行跨域
 ? Specify the URI that may access the API: https://xxx.com #需要跨域请求的域名
 ? Enter the HTTP methods that are allowed for CORS: GET, POST #方法
 ? Enter the HTTP headers that are allowed for CORS: Origin, Content-Type, X-Auth-Token, X-Requested-With,Accept, Authorization, X-CSRF-TOKEN, X-Socket-Id #header
 ? What do you want this config to be saved as? laravel-echo-server.json
 Configuration file saved. Run `laravel-echo-server start` to run server.
 $> laravel-echo-server start #这个东西我们可以先不用启动
 $> composer require predis/predis #安装 predis 包

第二步:开启 BroadcastServiceProvider 服务

目录:config/app.php

 'providers' => [
         /................../
        /*
         * Application Service Providers...
         */
        App\Providers\AppServiceProvider::class,
        App\Providers\AuthServiceProvider::class,
        App\Providers\BroadcastServiceProvider::class, # 这里需要打开注释
        App\Providers\EventServiceProvider::class,
        App\Providers\RouteServiceProvider::class,
    ],

第三步:配置 .env 文件的广播驱动为 redis

BROADCAST_DRIVER=redis #这里
CACHE_DRIVER=file
FILESYSTEM_DISK=local
QUEUE_CONNECTION=redis #广播走队列系统,所以这里也要改一下
SESSION_DRIVER=redis
SESSION_LIFETIME=120

MEMCACHED_HOST=127.0.0.1

REDIS_CLIENT=predis # 注意这里要用 predis
REDIS_HOST=127.0.0.1 # redis 地址
REDIS_PASSWORD=null # redis 密码
REDIS_PORT=6379  # redis 端口
#下面这三个东东也要配置哦,具体说明可以看下 laravel-echo-server 的 github 文档
LARAVEL_ECHO_SERVER_REDIS_HOST=127.0.0.1 # redis 地址
LARAVEL_ECHO_SERVER_REDIS_PASSWORD=null # redis 密码
LARAVEL_ECHO_SERVER_REDIS_PORT=6379 # redis 端口

第四步:因为 Laravel 会有 redis 前缀所以我们还需要配置一下 laravel-echo-server 的配置文件,加上这个前缀

{
    "authHost": "http://localhost",
    "authEndpoint": "/broadcasting/auth",
    "clients": [],
    "database": "redis",
    "databaseConfig": {
        "redis": {
            "keyPrefix": "laravel_database_" # 这里的 laravel 是根据 env 文件的 APP_NAME 变得,如果你改了 APP_NAME 那么这里也要改,举个例子:APP_NAME=Plant 那这里就是 plant_databases_
        },
        "sqlite": {
            "databasePath": "/database/laravel-echo-server.sqlite"
        }
    },
    "devMode": true,
    "host": null,
    "port": "6001",
    "protocol": "http",
    "socketio": {
        "path": "/chat" # 注意这里,如果你的服务器上面有多个 laravel-echo-server,那你肯定会遇到需要改变 socket.io 默认路径的问题,当然如果你只有一个项目那么就不需要咯
    },
    "secureOptions": 67108864,
    "sslCertPath": "",
    "sslKeyPath": "",
    "sslCertChainPath": "",
    "sslPassphrase": "",
    "subscribers": {
        "http": true,
        "redis": true
    },
    "apiOriginAllow": {
        "allowCors": true,
        "allowOrigin": "https://xxx.com",
        "allowMethods": "GET, POST",
        "allowHeaders": "Origin, Content-Type, X-Auth-Token, X-Requested-With, Accept, Authorization, X-CSRF-TOKEN, X-Socket-Id"
    }
}

第五步:打开 resource/js/bootstrap.js 修改为下面的配置

# 这里前面的内容省略啦~

import Echo from 'laravel-echo';
import io from 'socket.io-client';
window.io = io;
//
// import Pusher from 'pusher-js';
// window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'socket.io',
    host: window.location.hostname, # 这里也可以进行修改,比如我这边的服务是个单独的域名那么就可以写成 https://oooo.com
    path: "/chat", # 这里的路径要和 laravel-echo-serve.json 中 socket.io 一模一样,官方默认是 /socket.io 
    withCredentials: false
});

接下来就是生成编译文件

$> npm run dev #本地环境执行这个
$> npm run build #生产直接生成文件

第六步:开始试验广播

$> php artisan make:event ShippingStatusUpdated

修改文件内容

<?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 ShippingStatusUpdated implements ShouldBroadcast # 这里需要加上这个接口
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public int $id; #public 公开数据会通过广播推到前端~

    /**
     * Create a new event instance.
     */
    public function __construct($id) # 这里可以接受任何数据
    {
        $this->id = $id;
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return array<int, \Illuminate\Broadcasting\Channel>
     */
    public function broadcastOn(): array
    {
        return [
            new Channel('order'), # 通道名字
        ];
    }

    public function broadcastAs(): string
    {
        return 'OrderUpdated'; # 监听别名
    }
}

接下来就是前端页面

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Laravel</title>

    <!-- Fonts -->
    <link rel="preconnect" href="https://fonts.bunny.net">
    <script src="build/asset/app.xxxx.js"></script> <!-- 这里需要引入 npm run build 生产的 app.xxx.js 的文件,注意这里会生成两个要引入文件比较大的那个文件 -->
</head>
<body class="antialiased">
<script>
    window.onload = function () { // 为啥要用 onload 是因为 js 文件还没加载完成,就执行 window.Echo 会提示 undefined
        window.Echo.channel('order') // 这里监听的是通道名字
            .listen('.OrderUpdated', (e) => { // 这是监听的广播别名,事件别名
                console.log(e);
            });
        console.log(window.Echo);
    };
</script>
</body>
</html>

启动队列

php artisan queue:work

模拟执行一下,就可以收到消息了~

Route::get('/send', function () {
    event(new ShippingStatusUpdated(1));
});

Nginx代理问题:

由于我这边服务器上面有多个广播服务,所以我需要修改广播的默认 path 也就是 socket.io 的默认请求 path,下面是 nginx 的配置

# 这里是 socket.io 默认的 nginx 配置
location /socket.io {
    proxy_pass http://127.0.0.1:6003; #could be localhost if Echo and NginX are on the same box
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
}

# 当我们需要修改默认的 /socket.io 请求路由时,这里的 chat 就要和 laravel-echo-server.json 和 bootstrap.js 中的 path 相互对应,不然是走不通的,这块卡了我挺长时间,去看了 socket.io 的文档后才联想到这点。 
location /chat/{
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $host;
      proxy_pass http://localhost:6006;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
Web 开发者,Laravel 脑残粉,喜欢挑战探索新的东西,更喜欢完成一件有意义的事情之后的成就感!
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 4

直接使用soketi就可以了,为何这边要加入laravel-echo-server?

1年前 评论
Hollie (楼主) 1年前
91it (作者) 1年前
徵羽宫 1年前

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