用到得東西:
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 協議》,轉載必須註明作者和本文連結