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>
{{percentage}} % positiv