Ich schreibe ein Plugin für WordPress, das für jede Anfrage des Benutzers eine API aufrufen muss.
Diese API-Aufrufe erfolgen über das HTTPS-Protokoll. Derzeit muss ich für jede neue Benutzeranfrage die HTTPS-Verbindung erneut öffnen.
Ja, curl erlaubt dauerhafte Verbindungen (Wiederverwendung des Handles oder Verwendung des Multi-Handles), aber ich möchte die Verbindung über mehrere Benutzeranforderungen hinweg beibehalten.
Also: Ist es möglich, eine HTTPS-Verbindung über mehrere PHP-Prozesse offen zu halten und wiederzuverwenden? Die Alternative wäre, den Browser des Benutzers mit der API sprechen zu lassen. Aber wenn es geht würde ich das gerne vermeiden.
Während viele Ihnen sagen werden, dass PHP dafür nicht entwickelt wurde (und sie sind technisch korrekt), wurde diese Art von Problem bereits durch die Verwendung einer dauerhaften Ereignisschleife gelöst. Beispielsweise wird serverseitige Parallelität mit JavaScript erreicht, indem node.js verwendet wird, das eine Schleife startet, die auf einem einzelnen Thread läuft, der auf Ereignisse wartet. Anstelle des typischen PHP-Setups, das bei jeder Anfrage, die es vom Webserver erhält, einen neuen Thread startet, können Sie eine ähnliche Architektur mit dem (unglücklicherweise benannten) ReagierenPHP.
Der größte Haken an Ihrem Konzept ist, dass es als WordPress-Plugin läuft. WordPress neigt dazu äußerst kleinsten gemeinsamen Nenner, also müssen Sie einige Installationen ausschließen, wenn Sie möchten, dass dies funktioniert. Der größte Trick ist, dass Sie Ihre von WordPress gerouteten Seiten nicht (einfach) zum Laden aus dieser ReactPHP-Schleife verwenden können. Ich weiß, dass Sie versuchen, zusätzliche Verbindungen zu vermeiden, aber Sie können dies mit einer viel geringeren Latenz zum Laufen bringen, indem Sie sich mit Ihrem lokalen ReactPHP-Server verbinden, anstatt jedes Mal eine Remote-Verbindung herzustellen.
Wenn Ihr Server Ihnen Zugriff zum Öffnen einiger lokaler Ports gibt, können Sie einen neuen ReactPHP-Server wie folgt erstellen:
$socket = new React\Socket\Server(8080, $loop);
Wenn Sie keinen Portzugriff haben, können Sie Ihre Verbindung möglicherweise über einen lokalen Socket einrichten. Die Einrichtung kann etwas länger dauern und es wäre schwieriger, an einer allgemeinen Installation zu arbeiten:
$socket = new React\Socket\Server('unix://path/to/unix/socket', $loop);
Ich bin nicht durch die Schritte gegangen, um das einzurichten, aber wenn Sie können das zum Laufen bringen, ich denke, es wäre der zuverlässigste Ansatz für WordPress, da Sie immer einen gewissen Zugriff auf das Dateisystem in Ihren Plugins haben werden.
Sie sollten in der Lage sein zu sehen, wie Sie Ihre dauerhafte Verbindung unterbrechen können, entweder mit der Closure
Sie bauen Ihren Server mit oder einer statischen Klassenmethode (bevorzugt, da diese Klasse dann für die Wiederverbindung verantwortlich sein könnte, wenn sie gelöscht wird).
use React\Http\Server;
use Psr\Http\Message\ServerRequestInterface as Request;
use React\Http\Response;
use MyNamespace\Api\ExternalService;
$server = new Server(function (Request $request) {
$ch = ExternalService::getConnectionHandle();
// Do something with your $ch based on the $request here
return new Response(
200,
['Content-Type' => 'application/json'],
json_encode(/* some data from your request */)
);
});
Ich lasse das Schreiben ExternalService
bis zu Ihnen, da ich sicher bin, dass Sie hier bereits etwas eingerichtet haben.
Für Ihre WordPress-Seiten können sie jetzt ihre Anfragen an Ihr lokales ReactPHP mit extrem niedriger Latenz stellen. Du kannst es versuchen fsockoffen wenn Sie Sockets verwenden möchten, oder eine einfache Curl, wenn Sie dies über TCP tun.
Ein weiterer Knackpunkt wird die Initialisierung des Servers sein. Wenn es sich um einen Server handelt, der Ihnen gehört, auf den Sie Shell-Zugriff haben, kann er ausgeführt werden cron
Jobs oder haben exec()
Es ist ganz einfach: Führen Sie einfach Ihr Serverskript aus. Andernfalls müssen Sie einige Stunden investieren, um Ihren Server so zu konfigurieren, dass dieses Skript bei einer neuen Anfrage ausgeführt wird und es keine Zeitüberschreitung gibt.
Die andere Möglichkeit besteht darin, es umzudrehen: Wenn Sie die gesamte App unter ReactPHP bereitstellen können (anstatt zuerst den WP-Dispatcher zu treffen), können Sie dies ohne alle lokalen Verbindungen tun und direkt zur dauerhaften Verbindung springen. Das würde natürlich eine Verbreitung als WordPress-Plugin unmöglich machen.
Wenn alles gesagt und getan ist, sollten Sie sich fragen, ob es den Aufwand wirklich wert ist, die Latenz bei diesen Anfragen einzusparen. Ich bin nicht Sie, also kann ich es nicht sagen, aber wenn Sie wirklich weiterhin WordPress oder PHP verwenden müssen, können Sie es so tun. Sie werden feststellen, dass es ein exponentiell einfacheres Problem ist, wenn Sie den WordPress-Teil (vielleicht make //mydomain.com/blog
gehen Sie zu WP, und alles andere wird von Ihrer ReactPHP-App bedient). Wenn Sie von PHP weggehen können, bewegt es sich von einfacher zu wahrscheinlich einfacher zu konfigurieren mit einer dauerhaften Verbindung als ohne, da dies ein Standardansatz in Node oder Go ist. Architektonisch ist es nicht viel anders, als sich beim Start des Servers mit Ihrer DB zu verbinden, anstatt bei jeder Verbindung.
Am Ende habe ich diese Anfragen über den Browser gestellt. Browser halten HTTP(S)-Verbindungen offen, wenn der Server sie dazu auffordert.
Leider bringt diese Lösung einige Nachteile mit sich:
- Authentifizierung ist schwieriger
- mehr Last auf dem Server, da mehr Verbindungen aufrechterhalten werden müssen
- Die Lösung benötigt zusätzliches JavaScript
Aber Anfragen sind viel schneller (ca. 3x) und die Belastung des Servers, auf dem WordPress läuft, wird minimiert.
Dafür wurde PHP nicht entwickelt. Könnte man aber theoretisch Erstellen Sie einen Socket-Server in PHP, das auf einem eigenen Port außerhalb von Apache/nginx ausgeführt wird, und öffnen Sie die persistente HTTPS-Verbindung. Senden Sie dann alle Ihre Benutzeranforderungen an diesen Port, damit er den API-Aufruf verarbeiten kann.
– Rickdenhan
23. Juli 2017 um 12:26 Uhr
Oh, das ist böse. Ich müsste HTTP/S Server + Client implementieren UND es ist nicht garantiert, dass es funktioniert, da die WordPress-Site möglicherweise eine Firewall hat (sollte).
– JDemler
23. Juli 2017 um 12:30 Uhr
Wie lösen andere dieses Problem? Akzeptieren sie nur die massiven Latenzkosten für neue HTTPS-Verbindungen? Es muss Leute geben, die PHP-Code schreiben, die das nicht akzeptieren können.
– JDemler
23. Juli 2017 um 12:31 Uhr
Nun, technisch gesehen ist HTTPS auch darauf ausgelegt, jeweils eine einzelne Anfrage auszuführen. Also ja, so ziemlich jeder akzeptiert den Overhead mehrerer Verbindungen. Die meisten Remote-APIs sind nicht darauf ausgelegt, mehrere Anfragen über eine einzige HTTPS-Verbindung zu akzeptieren.
– Rickdenhan
23. Juli 2017 um 12:32 Uhr
Willst du mich verarschen? Wirklich? Warum können die meisten APIs nicht mehrere Anfragen über HTTPS akzeptieren? Setzen Sie einfach ein NGINX davor … Sie verschwenden bei jeder Anfrage etwa das 3,5-fache der Latenz? Irgendetwas scheint hier wirklich nicht zu stimmen…
– JDemler
23. Juli 2017 um 12:39 Uhr