
問題点
ブラウザから、laravel-echo-serverに接続しようとするとERR_CONNECTION_RESETのエラーが発生し、WebSocket通信が開始されない。
構築したdockerの構成
使用サーバ一覧
以下のコンテナ名を使用しています。
- nginx
- php-fpm
- echo-server←今回接続できていないサーバ
- mysql
- redis
- npm(JavaScriptビルド用)
- npmi(npm install用)
- composer(composer install用)
使用したdocker-compose.yaml及びdockerfile
docker
1version: '3' 2services: 3 nginx: 4 image: nginx:latest 5 volumes: 6 - ./src/laravel:/usr/share/nginx/html 7 - ./container/nginx/default.conf:/etc/nginx/conf.d/default.conf 8 ports: 9 - 80:80 10 links: 11 - php-fpm 12 composer: 13 image: composer:latest 14 command: composer install 15 working_dir: /data 16 volumes: 17 - ./src/laravel:/data 18 php-fpm: 19 build: ./container/php-fpm 20 volumes: 21 - ./src/laravel:/var/www/html 22 - ./container/php-fpm/www.conf:/usr/local/etc/php-fpm.d/www.conf 23 depends_on: 24 - composer 25 links: 26 - mysql 27 - redis 28 npm: 29 build: ./container/npm 30 command: npm run watch-poll 31 working_dir: /data 32 volumes: 33 - ./src/laravel:/data 34 depends_on: 35 - npmi 36 npmi: 37 build: ./container/npm 38 command: npm i 39 working_dir: /data 40 volumes: 41 - ./src/laravel:/data 42 echo-server: 43 build: ./container/npm 44 command: laravel-echo-server start 45 working_dir: /data 46 volumes: 47 - ./src/laravel:/data 48 expose: 49 - 6001 50 links: 51 - redis 52 ports: 53 - 6001:6001 54 mysql: 55 image: mysql:8.0 56 command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci 57 environment: 58 MYSQL_DATABASE: phpunit_tester 59 MYSQL_ROOT_PASSWORD: password 60 MYSQL_USER: phpunit_tester 61 MYSQL_PASSWORD: password 62 TZ: Asia/Tokyo 63 ports: 64 - 3306:3306 65 volumes: 66 - ./container/mysql/data:/var/lib/mysql 67 - ./container/mysql/initdb.d:/docker-entrypoint-initdb.d 68 redis: 69 image: redis:latest 70 ports: 71 - 6379:6379
container/npm/Dockerfle
1FROM alpine:latest 2 3# ホストのUIDと同条件のユーザを作成 4ARG DOCKER_UID=1000 5ARG DOCKER_USER=docker 6ARG DOCKER_PASSWORD=docker 7RUN adduser -s /bin/ash -u ${DOCKER_UID} ${DOCKER_USER} -D && \ 8# npmのインストール 9apk add --update nodejs npm && \ 10npm i -g laravel-echo-server 11# デフォルトユーザの変更 12USER ${DOCKER_USER}
php-fpmでも、Dockerfileを使用していますが、今回はあまり関係なさそうなため、省略します。
使用したlaravel-echo-server.json
laravel
1{ 2 "authHost": "http://localhost", 3 "authEndpoint": "/broadcasting/auth", 4 "clients": [ 5 { 6 "appId": "83a5c632a785327f", 7 "key": "576186c4d59b7dd113c75a786328b9d7" 8 } 9 ], 10 "database": "redis", 11 "databaseConfig": { 12 "redis": { 13 "port": "6379", 14 "host": "redis", 15 "keyPrefix": "phpunit-tester-echo-server" 16 }, 17 "sqlite": { 18 "databasePath": "/database/laravel-echo-server.sqlite" 19 } 20 }, 21 "devMode": true, 22 "host": "localhost", 23 "port": "6001", 24 "protocol": "http", 25 "socketio": { 26 "wsEngine": "ws" 27 }, 28 "secureOptions": 67108864, 29 "sslCertPath": "", 30 "sslKeyPath": "", 31 "sslCertChainPath": "", 32 "sslPassphrase": "", 33 "subscribers": { 34 "http": true, 35 "redis": true 36 }, 37 "apiOriginAllow": { 38 "allowCors": true, 39 "allowOrigin": "http://localhost:80", 40 "allowMethods": "GET, POST", 41 "allowHeaders": "Origin, Content-Type, X-Auth-Token, X-Requested-With, Accept, Authorization, X-CSRF-TOKEN, X-Socket-Id" 42 } 43}
フロントエンド側の実装
まず、laravel側のルーティングを以下のようにしました
web.php
1 2Route::get('/listener', function(){ 3 $hello = "Hello World!"; 4 return view('listener'); 5});
viewファイルはnpmでビルドしたapp.jsを使用しています。
listener.blade.php
1<html lang='ja'> 2<head> 3 <meta charset="utf-8"> 4 <meta name="csrf-token" content="{{csrf_token()}}"> 5</head> 6<body> 7listener 8<div id='app'></div> 9<script src="{{ asset('js/app.js') }}"></script> 10</body> 11</html>
bootstrap.jsをecho-serverに対応させることで、リクエストは投げられることが確認できましたが、ERR_CONNECTION_RESETのエラーが出てきてしまい、接続できませんでした。
bootstrap.js
1window._ = require('lodash'); 2 3/** 4 * We'll load the axios HTTP library which allows us to easily issue requests 5 * to our Laravel back-end. This library automatically handles sending the 6 * CSRF token as a header based on the value of the "XSRF" token cookie. 7 */ 8 9window.axios = require('axios'); 10 11window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; 12 13/** 14 * Echo exposes an expressive API for subscribing to channels and listening 15 * for events that are broadcast by Laravel. Echo and event broadcasting 16 * allows your team to easily build robust real-time web applications. 17 */ 18 19import Echo from 'laravel-echo'; 20 21window.io = require('socket.io-client') 22 23window.Echo = new Echo({ 24 broadcaster: 'socket.io', 25 host: 'http://localhost:6001' 26 27}); 28 29window.Echo.channel('public-event') 30.listen('PublicEvent', (e) =>{ 31 console.log(e) 32}); 33
これをapp.jsでrequireしたものをbuildしているだけです。
発生したエラー
(追記: この挙動Chromiumでのものです。)
http://localhost/listenerに接続するとDeveloper tool のNetworkタブに以下のエラーが出ました。
RequestURL: http://localhost:6001/socket.io/?EIO=3&transport=polling&t=M-OK9jG
RequestMethod: GET
エラー:
net::ERR_CONNECTION_RESET
(たまに、net::ERR_SOCKET_NOT_CONNECTEDが出ることもあるようです。)
確認したこと
ポートの開放確認
ホスト機から以下のコマンドを送信しました。
$ nc -vz localhost 6001
結果は以下のとおりです。
Connection to localhost 6001 port [tcp/x11-1] succeeded!
Firefoxでの接続確認
Firefoxでの接続の場合、エラーが以下のようになりました。
クロスオリジン要求をブロックしました: 同一生成元ポリシーにより、http://localhost:6001/socket.io/?EIO=3&transport=polling&t=M-OZGN7 にあるリモートリソースの読み込みは拒否されます (理由: CORS 要求が成功しなかった)。
知りたいこと
Laravel-Echo-Serverにきちんと接続できる方法。
retlatさんの解答を受けて、、、
内部トラフィック増えそうといったけれど、本番環境でロードバランサ噛ませるなら、別にそれでもいいかな、と思いつつ…ただ、なんか気持ち悪いので、別ポートで接続できるようにしたい。