(0)
Artikel
bewerten
(100% positiv)
(2)

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>


Kommentare


Laravel  Pusher

Laravel Pusher

Einfaches Beispiel zu Laravel Pusher.

 

Voraussetzung für die Funktion ist ein Online-Konto auf pusher.com: https://dashboard.pusher.com . Die Einrichtung von Pusher ist einfacher als Socket.io und ist für eine beschränkte Anzahl an Events kostenlos, siehe: pusher.com/channels/pricing 

Laravel Pusher


Laravel Echo socket.io - https 443 - ReverseProxy

Laravel Echo socket.io - https 443 - ReverseProxy

Wer seinen eigenen WebSocket-Server betreiben will kann, Anstelle von Pusher, auch Laravel ECHO in Kombination mit socket.io verwenden.

Sollte der ECHO-Server direkt am Webserver betrieben werden, kann dieser nicht denselben Port verwenden: der Browser muss sich zusätzlich auf einen anderen Port verbinden, was bei bestimmten Internetzugängen, speziell beim Einsatz eines Proxys zu Problemen führt. Alternativ kann der socket.io-Traffic auch über einen Reverse-Proxy am Webserver umgeleitet werden. Beim Einsatz eines Reverse-Proxy kann sich der Browser sowohl auf die Webseite, als auch auf den ECHO Server über Port 443 verbinden.

Laravel Echo socket.io - https 443 - ReverseProxy