Laravel10,Laravel廣播,Laravel-echo使用

Hollie發表於2023-03-10

用到得東西:

  • 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 包

目錄: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,
    ],
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 埠
{
    "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"
    }
}
# 這裡前面的內容省略啦~

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));
});

由於我這邊伺服器上面有多個廣播服務,所以我需要修改廣播的預設 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 腦殘粉,喜歡挑戰探索新的東西,更喜歡完成一件有意義的事情之後的成就感!

相關文章