Weiterverarbeitung von PHP nach dem Senden der HTTP-Antwort
Lesezeit: 7 Minuten
Benutzer1700214
Mein Skript wird vom Server aufgerufen. Vom Server erhalte ich ID_OF_MESSAGE und TEXT_OF_MESSAGE.
In meinem Skript werde ich eingehenden Text verarbeiten und eine Antwort mit Parametern generieren: ANSWER_TO_ID und RESPONSE_MESSAGE.
Das Problem ist, dass ich eine Antwort an eingehende sende "ID_OF_MESSAGE"aber der Server, der mir eine zu bearbeitende Nachricht sendet, setzt seine Nachricht als an mich zugestellt (das bedeutet, dass ich ihm eine Antwort an diese ID senden kann), nachdem er die HTTP-Antwort 200 erhalten hat.
Eine Lösung besteht darin, die Nachricht in der Datenbank zu speichern und einen Cron zu erstellen, der jede Minute ausgeführt wird, aber ich muss sofort eine Antwortnachricht generieren.
Gibt es eine Lösung, wie man die HTTP-Antwort 200 an den Server sendet und dann mit der Ausführung des PHP-Skripts fortfährt?
Vielen Dank
vcampitelli
Jawohl. Du kannst das:
ignore_user_abort(true);//not required
set_time_limit(0);
ob_start();
// do initial processing here
echo $response; // send the response
header('Connection: close');
header('Content-Length: '.ob_get_length());
ob_end_flush();
@ob_flush();
flush();
fastcgi_finish_request();//required for PHP-FPM (PHP > 5.3.3)
// now the request is sent to the browser, but the script is still running
// so, you can continue...
die(); //a must especially if set_time_limit=0 is used and the task ends
Ist es möglich, dies mit einer Keep-Alive-Verbindung zu tun?
– Congelli501
9. Juli 2014 um 19:14 Uhr
Exzellent!! Dies ist die einzige Antwort auf diese Frage, die wirklich funktioniert!!! 10p+
– Martin_Seen
1. August 2014 um 19:13 Uhr
Tolle Antwort! Das einzige, was ich geändert habe, war set_time_limit(0);. Sie möchten wahrscheinlich, dass es länger als die standardmäßigen 30 Sekunden läuft, aber auf unbestimmte Zeit könnte es zu Problemen kommen, wenn es in eine Endlosschleife geht! Ich habe einen längeren Wert in meinem eingestellt php.ini Datei.
– CJ Dennis
21. August 2014 um 14:25 Uhr
Bitte beachten Sie, dass wenn ein Content-Encoding-Header auf etwas anderes als „none“ gesetzt ist, dieses Beispiel unbrauchbar werden könnte, da es den Benutzer immer noch die volle Ausführungszeit (bis zum Timeout?) warten lassen würde. Um absolut sicher zu sein, dass es lokal und in der Produktionsumgebung funktioniert, setzen Sie den Header „content-encoding“ auf „none“: header("Content-Encoding: none")
– Brian
25. Juni 2015 um 7:04 Uhr
Tipp: Ich habe angefangen, PHP-FPM zu verwenden, also musste ich hinzufügen fastcgi_finish_request() Am Ende
– vcampitelli
16. September 2015 um 13:18 Uhr
Kosta Kontos
Ich habe hier viele Antworten gesehen, die die Verwendung vorschlagen ignore_user_abort(true); aber dieser Code ist nicht notwendig. All dies stellt sicher, dass Ihr Skript weiter ausgeführt wird, bevor eine Antwort gesendet wird, falls der Benutzer abbricht (indem er seinen Browser schließt oder die Escape-Taste drückt, um die Anfrage zu stoppen). Aber danach fragst du nicht. Sie bitten darum, die Ausführung fortzusetzen, NACHDEM eine Antwort gesendet wurde. Alles, was Sie brauchen, ist Folgendes:
// Buffer all upcoming output...
ob_start();
// Send your response.
echo "Here be response";
// Get the size of the output.
$size = ob_get_length();
// Disable compression (in case content length is compressed).
header("Content-Encoding: none");
// Set the content length of the response.
header("Content-Length: {$size}");
// Close the connection.
header("Connection: close");
// Flush all output.
ob_end_flush();
@ob_flush();
flush();
// Close current session (if it exists).
if(session_id()) session_write_close();
// Start your background work here.
...
Wenn Sie befürchten, dass Ihre Hintergrundarbeit länger dauert als das standardmäßige Zeitlimit für die Skriptausführung von PHP, dann bleiben Sie set_time_limit(0); oben.
Ich habe viele verschiedene Kombinationen ausprobiert, DAS ist diejenige, die funktioniert !!! Danke Kosta Kontos!!!
– Martin_Seen
5. August 2016 um 10:43 Uhr
Funktioniert perfekt auf Apache 2, PHP 7.0.32 und Ubuntu 16.04! Danke!
– KyleBunga
26. Januar 2019 um 0:03 Uhr
Ich habe andere Lösungen ausprobiert, und nur diese hat bei mir funktioniert. Die Reihenfolge der Zeilen ist ebenfalls wichtig.
– Siniša
1. Oktober 2019 um 15:27 Uhr
Ich kann beim besten Willen nicht verstehen, warum ob_flush() ist hier erforderlich, da es eine Benachrichtigung auslöst PHP Notice: ob_flush(): failed to flush buffer. No buffer to flush in php shell code on line 1. Ohne geht das komischerweise nicht. Ich schätze, es tut doch etwas…
– Von einem Grue gefressen
23. Juli 2021 um 11:20 Uhr
@billynoah Ich denke, es wird nicht benötigt. ob_end_flush() macht das gleiche wie ob_flush außer dass es den Puffer schließt (daher Aufruf ob_flush() nach dem ob_end_flush() erzeugt die Warnung, auf die Sie gestoßen sind.
– Sebi2020
3. September 2021 um 18:25 Uhr
DarkNeuron
Wenn Sie FastCGI-Verarbeitung oder PHP-FPM verwenden, können Sie:
session_write_close(); //close the session
ignore_user_abort(true); //Prevent echo, print, and flush from killing the script
fastcgi_finish_request(); //this returns 200 to the user, and processing continues
// do desired processing ...
$expensiveCalulation = 1+1;
error_log($expensiveCalculation);
Danke dafür, nachdem ich ein paar Stunden damit verbracht hatte, funktionierte dies für mich in nginx
– Ehsan
14. Februar 2017 um 8:33 Uhr
Danke DarkNeuron! Tolle Antwort für uns mit php-fpm, gerade mein Problem gelöst!
– Siniša
1. Januar 2020 um 6:54 Uhr
Brillant! Ich habe gerade Stunden damit verbracht, herauszufinden, warum unsere App auf einer Seite, auf der wir die Ausgabepufferung verwendet haben, nicht mehr funktioniert, nachdem wir sie auf einen neuen Server verschoben haben, und das war der Schlüssel. Danke!
– D Durham
12. Dezember 2020 um 16:04 Uhr
Einfach und effizient, der Code, den wir mögen. Danke
– PaulCrp
20. Februar um 18:44 Uhr
Ich habe ein paar Stunden mit diesem Problem verbracht und bin mit dieser Funktion gekommen, die auf Apache und Nginx funktioniert:
/**
* respondOK.
*/
protected function respondOK()
{
// check if fastcgi_finish_request is callable
if (is_callable('fastcgi_finish_request')) {
/*
* This works in Nginx but the next approach not
*/
session_write_close();
fastcgi_finish_request();
return;
}
ignore_user_abort(true);
ob_start();
$serverProtocole = filter_input(INPUT_SERVER, 'SERVER_PROTOCOL', FILTER_SANITIZE_STRING);
header($serverProtocole.' 200 OK');
header('Content-Encoding: none');
header('Content-Length: '.ob_get_length());
header('Connection: close');
ob_end_flush();
ob_flush();
flush();
}
Sie können diese Funktion vor Ihrer langen Verarbeitung aufrufen.
Die Antwort von @vcampitelli wurde etwas geändert. Denke nicht, dass du das brauchst close Header. Ich habe in Chrome doppelte geschlossene Header gesehen.
Ich habe dies in der ursprünglichen Antwort erwähnt, aber ich werde es auch hier sagen. Sie müssen die Verbindung nicht unbedingt schließen, aber dann wird das nächste Asset, das auf derselben Verbindung angefordert wird, warten müssen. Sie könnten also den HTML-Code schnell bereitstellen, aber dann könnte eine Ihrer JS- oder CSS-Dateien langsam geladen werden, da die Verbindung die Antwort von PHP erhalten muss, bevor sie das nächste Asset erhalten kann. Aus diesem Grund ist es eine gute Idee, die Verbindung zu schließen, damit der Browser nicht auf die Freigabe warten muss.
– Nate Lampton
17. September 2015 um 3:42 Uhr
Ich verwende dafür die PHP-Funktion register_shutdown_function.
Bearbeiten: Das obige funktioniert nicht. Anscheinend wurde ich von einer alten Dokumentation in die Irre geführt. Das Verhalten von register_shutdown_function hat sich seit PHP 4.1 geändert VerknüpfungVerknüpfung
Ich habe dies in der ursprünglichen Antwort erwähnt, aber ich werde es auch hier sagen. Sie müssen die Verbindung nicht unbedingt schließen, aber dann wird das nächste Asset, das auf derselben Verbindung angefordert wird, warten müssen. Sie könnten also den HTML-Code schnell bereitstellen, aber dann könnte eine Ihrer JS- oder CSS-Dateien langsam geladen werden, da die Verbindung die Antwort von PHP erhalten muss, bevor sie das nächste Asset erhalten kann. Aus diesem Grund ist es eine gute Idee, die Verbindung zu schließen, damit der Browser nicht auf die Freigabe warten muss.
– Nate Lampton
17. September 2015 um 3:42 Uhr
Matthäus Slyman
Diese Frage habe ich Rasmus Lerdorf im April 2012 gestellt und diese Artikel zitiert:
Ich habe die Entwicklung einer neuen in PHP integrierten Funktion vorgeschlagen, um die Plattform zu benachrichtigen, dass keine weitere Ausgabe (auf stdout?) Generiert wird (eine solche Funktion könnte sich um das Schließen der Verbindung kümmern). Rasmus Lerdorf antwortete:
Sehen Getriebemann. Sie möchten wirklich nicht, dass Ihre Frontend-Webserver eine solche Backend-Verarbeitung durchführen.
Ich kann seinen Standpunkt verstehen und seine Meinung für einige Anwendungen / Ladeszenarien unterstützen! Unter einigen anderen Szenarien sind die Lösungen von vcampitelli et al. jedoch gut.
9832900cookie-checkWeiterverarbeitung von PHP nach dem Senden der HTTP-Antwortyes