Laravel Websockets 443 über https - 443

 

Mit Hilfe von WebSockets können Echtzeit-Webanwendungen umgesetzt werden. WebSockets ermöglichen dem Browser auf bestimmte Anforderungen vom Server zu warten, der Browser muss also nicht regelmäßig nach Updates vom Server fragen, er wird vom Server aktiv informiert. 

Eine WebSockets-Lösung kann in Laravel mit Pusher oder socket.io implementiert werden. Hier ein einfaches Beispiel, die spezifischen Einstellungen für Pusher und ECHO mit socket.io folgen im Anschluss.

Beispiel

Der Browser erstellt mittels Javascript eine WebSocket-Verbindung zu Pusher oder einem eigenen socket.io Server.

Ich verwende dazu die URL: /eventtest

An dieser Stelle wartet der Browser auf Events vom Server.

Beim Aufruf der URL /eventfire wird ein Event ausgelöst:

Die URL /eventtest wird über das Auslösen des Events informiert und regiert darauf mit einem Alert:

/routes/web.php

Für den Aufruf der beiden Seiten erstellen wir 2 Routes

use App\Events\EventTrigger;

Route::view('/eventtest', 'eventListener');
route::get('/eventfire', function () {
event(new EventTrigger());
});

/eventtest lädt eine View

/eventfire lädt direkt einen Event, welchen wir wie folgt erstellen können:

Trigger

php artisan make:event EventTrigger

 /app/Events/EventTrigger.php

<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

class EventTrigger implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new Channel('channel-test');
    }
}

In der Datei /config/app.php muss zudem die Zeile: App\Providers\BroadcastServiceProvider::class, aktiviert werden, diese ist standardmäßig auskommentiert

ShouldBroadcast vs. ShouldBroadcastNow

ShouldBroadcast verwendet den Standard-Queue-Driver, ShouldBroadcastNow verwendet "sync" als Queue-Driver, Events werden also sofort rausgeschickt.

Sollte der Standard-Queue-Driver sync sein, macht es also keinen Unterschied ob ShouldBroadcastNow oder ShouldBroadcast verwendet wird.

Redis als Queue-Driver:

Sollte als Queue-Driver Redis zum Einsatz kommen, in der .env -Datei wird also

QUEUE_DRIVER=redis 

verwendet, wird für das Abhandeln der Events noch ein laufender Queue-Worker benötigt:

Konsole: php artisan queue:work redis

Wie vorhin beschrieben muss dazu ShouldBroadcast und nicht ShouldBroadcastNow in EventTrigger.php verwendet werden.

Voraussetzung ist die Installation des Redis-Servers, siehe: www.libe.net/ubuntu-redis zudem muss Redis in der .env-Datei konfiguriert werden:

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=???
REDIS_PORT=6379
permantentes Ausführen des Queue Workers:

Ubuntu/Debian sudo apt-get install supervisor

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/vhosts/domain/laravelfolder/artisan queue:work redis --sleep=3 --tries=3
autostart=true
autorestart=true
user=root
numprocs=8
redirect_stderr=true
stdout_logfile=/var/www/vhosts/domain/laravelfolder/laravel/storage/logs/worker.log
sudo supervisorctl stop all 
sudo supervisorctl reread
sudo supervisorctl reload

Der Status kann mit

supervisorctl status

überprüft werden ...

/resources/views/eventListener.blade.php

<!DOCTYPE html>
<html>
  <head>
      <title>EventTest</title>
	    <link rel="stylesheet" href="/css/app.css">
	  	<meta name="csrf-token" content="{{ csrf_token() }}">
  </head>
  <body>
	<div id="app2">
		<p>test</p>
	</div>
 	<script src="/js/app.js" charset="utf-8"></script>   
 	<script>
 	new Vue({
 		el: '#app2',

 		created() {
 			Echo.channel('channel-test').listen('EventTrigger', (e) => {
 			 alert('EventTriggered');
 			};
 		}
 	});</script>
  </body>
</html>

Private

/app/Events/EventTrigger.php: PrivateChannel

<?php

namespace App\Events;
use Illuminate\Support\Facades\Auth;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;


class EventTrigger implements ShouldBroadcastNow
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct()
    {
        
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    { 
        return new PrivateChannel('App.User.'.  Auth::user()->id );
    }
}

routes/channels.php - Client can not be authenticated, got HTTP status 403

Damit die Authentifizierung für private Channels überprüft wird, müssen die User in channels.php überprüft werden.

Broadcast::channel('App.User.{id}', function ($user, $id) {
    return (int) $user->id === (int) $id;
});

Sollte die Überprüfung fehlschlagen, taucht im Log des Echo-Servers folgender Fehler auf: Client can not be authenticated, got HTTP status 403

/resources/views/eventListener.blade.php

<!DOCTYPE html>
<html>
  <head>
      <title>EventTest</title>
	    <link rel="stylesheet" href="/css/app.css">
	  	<meta name="csrf-token" content="{{ csrf_token() }}">
  </head>
  <body> 
	<div id="app2">
		<p>test</p>
	</div>
 	<script src="/js/app.js" charset="utf-8"></script>   
	  <script>
		  const app2 = new Vue({
	el: '#app2',
	created() {
		Echo.private('App.User.{{ Auth::user()->id }}')
		.listen('EventTrigger', (e) => {
		 alert('EventTriggered');
		});
		}
	});
	 </script>
  </body>
</html>
positive Bewertung({{pro_count}})
Beitrag bewerten:
{{percentage}} % positiv
negative Bewertung({{con_count}})

DANKE für deine Bewertung!

Fragen / Kommentare