#はじめに
Googleで検索すると、Laravelの公式ドキュメントや他の記事でLaravelとRedisを用いたWebSocket通信のやり方がたくさんでてきましたが、どれを試してなかなか上手くいかず苦戦したので、メモ代わりに記事に残します。各ツールの説明は省略します。検索した方が分かりやすい記事がたくさん出てくると思うので...。
#環境
Docker Desktop for Mac 3.6.0
PHP 8.0.9
Laravel 8.40
redis-server 6.2.5
Laravel-echo-server 1.6.2
node 14.16.0
npm 7.8.0
composer 1.10.19
#dockerでコンテナを構築
今回は下記の記事で作成したDokcer環境をベースに必要なものを追加しました。@ucan-lab さん、ありがとうございます。
【超入門】20分でLaravel開発環境を爆速構築するDockerハンズオン
##プロジェクト構成
.
├── infra
│ ├── echo-server
│ │ └──Dockerfile
│ ├── mysql
│ │ ├── Dockerfile
│ │ └── my.cnf
│ ├── nginx
│ │ └── default.conf
│ ├── php
│ │ ├── Dockerfile (この名前にするとファイル名の指定を省略できる)
│ │ └── php.ini
│ └── redis
│ └── data(ディレクトリです)
├── docker-compose.yml (この名前にするとファイル名の指定を省略できる)
└── backend
└── Laravelをインストールするディレクトリ
各ファイルの中身
version: "3.9"
services:
app:
build: ./infra/php
volumes:
- ./backend:/work
web:
image: nginx:1.20-alpine
ports:
- 8080:80
volumes:
- ./backend:/work
- ./infra/nginx/default.conf:/etc/nginx/conf.d/default.conf
working_dir: /work
db:
build: ./infra/mysql
ports:
- 33060:3306
volumes:
- db-store:/var/lib/mysql
echo-server:
image: broadcast-echo-server
build: ./infra/echo-server
ports:
- "6001:6001"
command: laravel-echo-server start
volumes:
- ./backend:/work
working_dir: /work
redis:
image: redis:latest
ports:
- 6379:6379
volumes:
- "./infra/redis/data:/data"
volumes:
db-store:
FROM node:13.8-alpine
RUN npm install -g laravel-echo-server
WORKDIR /work
CMD ["laravel-echo-server", "start"]
FROM mysql/mysql-server:8.0
ENV MYSQL_DATABASE=laravel_local \
MYSQL_USER=phper \
MYSQL_PASSWORD=secret \
MYSQL_ROOT_PASSWORD=secret \
TZ=Asia/Tokyo
COPY ./my.cnf /etc/my.cnf
RUN chmod 644 /etc/my.cnf
[mysqld]
# default
skip-host-cache
skip-name-resolve
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
secure-file-priv=/var/lib/mysql-files
user=mysql
pid-file=/var/run/mysqld/mysqld.pid
# character set / collation
character_set_server = utf8mb4
collation_server = utf8mb4_ja_0900_as_cs_ks
# timezone
default-time-zone = SYSTEM
log_timestamps = SYSTEM
# Error Log
log-error = mysql-error.log
# Slow Query Log
slow_query_log = 1
slow_query_log_file = mysql-slow.log
long_query_time = 1.0
log_queries_not_using_indexes = 0
# General Log
general_log = 1
general_log_file = mysql-general.log
[mysql]
default-character-set = utf8mb4
[client]
default-character-set = utf8mb4
server {
listen 80;
server_name example.com;
root /work/public;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.php;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_pass app:9000;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
FROM php:8.0-fpm-buster
SHELL ["/bin/bash", "-oeux", "pipefail", "-c"]
ENV COMPOSER_ALLOW_SUPERUSER=1 \
COMPOSER_HOME=/composer
COPY --from=composer:2.0 /usr/bin/composer /usr/bin/composer
RUN apt-get update && \
apt-get -y install git unzip libzip-dev libicu-dev libonig-dev && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
docker-php-ext-install intl pdo_mysql zip bcmath
COPY ./php.ini /usr/local/etc/php/php.ini
RUN curl -sL https://deb.nodesource.com/setup_14.x | bash -
RUN apt-get install -y nodejs
RUN npm install npm@latest -g
WORKDIR /work
zend.exception_ignore_args = off
expose_php = on
max_execution_time = 30
max_input_vars = 1000
upload_max_filesize = 64M
post_max_size = 128M
memory_limit = 256M
error_reporting = E_ALL
display_errors = on
display_startup_errors = on
log_errors = on
error_log = /dev/stderr
default_charset = UTF-8
[Date]
date.timezone = Asia/Tokyo
[mysqlnd]
mysqlnd.collect_memory_statistics = on
[Assertion]
zend.assertions = 1
[mbstring]
mbstring.language = Japanese
#Laravelをインストール
Dockerコンテナを立ち上げた後、Laravelをインストールします。
Laravelのインストールから環境構築までは下記記事と同様のやり方なので、参考にしてください。
【超入門】20分でLaravel開発環境を爆速構築するDockerハンズオン
#Laravel-echo-serverの設定
初回コンテナ起動時、Laravel-echo-serverの初期設定がすんでないため、エラーが発生するので、初期設定を行います。
$ docker compose run echo-server laravel-echo-server init
? Do you want to run this server in development mode? Yes
? Which port would you like to serve from? 6001
? Which database would you like to use to store presence channel members? redis
? Enter the host of your Laravel authentication server. https://localhost
? Will you be serving on http or https? http
? Do you want to generate a client ID/Key for HTTP API? No
? Do you want to setup cross domain access to the API? No
? 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プロジェクト直下にlaravel-echo-server.jsonというファイルが作成されているので、以下のように書き換えます。
{
"authHost": "http://localhost",
"authEndpoint": "/broadcasting/auth",
"clients": [],
"database": "redis",
"databaseConfig": {
"redis": {
"host": "redis",
"port": 6379
},
"sqlite": {
"databasePath": "/database/laravel-echo-server.sqlite"
}
},
"devMode": true,
"host": null,
"port": "6001",
"protocol": "http",
"socketio": {},
"secureOptions": 67108864,
"sslCertPath": "",
"sslKeyPath": "",
"sslCertChainPath": "",
"sslPassphrase": "",
"subscribers": {
"http": true,
"redis": true
},
"apiOriginAllow": {
"allowCors": false,
"allowOrigin": "",
"allowMethods": "",
"allowHeaders": ""
}
}
#必要なライブラリを追加
"require": {
// 他省略
"predis/predis": "^1.1"
}
"dependencies": {
// 他省略
"laravel-echo": "^1.11.1",
"laravel-echo-server": "^1.6.2",
"socket.io": "^2.4.0",
"socket.io-client": "^2.4.0",
}
#各種設定
###プロバイダーの設定
app/config/app.phpの以下の部分のコメントアウトを外す
App\Providers\BroadcastServiceProvider::class,
###redisの設定
'redis' => [
'client' => env('REDIS_CLIENT', 'predis'),
'default' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => 0,
],
'cache' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => 1,
],
'options' => [
'prefix' => env('REDIS_PREFIX', ''),
],
],
###.envファイルの変更
BROADCAST_DRIVER=redis
QUEUE_CONNECTION=redis
REDIS_HOST=redis
REDIS_CLIENT=predis
REDIS_PASSWORD=null
REDIS_PORT=6379
REDIS_PREFIX=""
ここまででWebSocketによるリアルタイム通信を行えるようになりました。
#実際に送ってみる
LaravelのEvent機能を使ってクライアント側にリアルタイムでデータを送信します。
##サーバーサイドの準備
###Eventの作成
php artisan make:event MessageRecieved
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class MessageReceived implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new Channel('test');
}
public function broadcastWith()
{
return [
'data' => 'test',
];
}
}
###Event発火の準備
今回はルートにアクセスしたときにEventを発火させます。
Route::get('/', function () {
event(new \App\Events\MessageReceived());
return view('welcome');
});
ワーカーの起動
Redisによる処理をキューで実行するのでワーカーを起動しておく
php artisan queue:work
クライアントサイドの準備
ビューの準備
ルートで表示するビューを以下のようにします。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>Laravel</title>
<link rel="stylesheet" href="{{ mix('css/app.css') }}">
</head>
<body>
<div id="app">
test
</div>
<script src="{{ mix('js/app.js') }}"></script>
<script src="http://{{ Request::getHost() }}:6001/socket.io/socket.io.js"></script>
</body>
</html>
###スクリプトの準備
bootstrap.jsに以下を追記します。
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("test").listen("MessageReceived", e => {
console.log("メッセージ受け取り成功!!!");
});
###コンパイルする
npm install && npm run dev
##実行
chromeのデベロッペーツールのConsole画面を開いて
http://127.0.0.7:8080 に接続すると
無事、クライアントでメッセージを受け取れてます。
##動かないとき
Dockerの再起動でうまくいく場合があります。
それでもうまくいかない場合は、Dockerのログを確認しましょう。
docker compose logs
#さいごに
今回はメモ代わりということでコードをベタ貼りしていく形になりました。ちなみにPusherというサービスを使えば、超簡単にリアルタイム通信が可能です。Laravelの公式ドキュメントにも記載されているので、気になった方はぜひ。