Wenn ich mit AJAX arbeite, das ich als JSON zurückgebe, verwende ich einen Trick, um die Ausgabepufferung zu nutzen. Sie können nicht einfach alles echoen oder ausgeben, was Sie möchten, da dies die JSON-Daten durcheinander bringt, also zum Beispiel
ob_start(); //turn on buffering at beginning of script.
.... other code ...
print_r($somevar);
.... other code ...
$debug = ob_get_clean(); //put output in a var
$data['debug'] = $debug;
header('Content-Type: application/json');
echo json_encode($data); //echo JSON data.
Dadurch wird jede Ausgabe Ihres Skripts in Ihre JSON-Daten eingeschlossen, sodass das Format nicht verfälscht wird.
Dann können Sie auf der Javascript-Seite die Datei console.log
verwenden$.post(url, input, function(data){
if(data.debug) console.log(data.debug);
});
Wenn Sie das Debuggen mit console.log()
nicht gewohnt sind , können Sie normalerweise F12
drücken und öffnen Sie den Debugger in den meisten Browsern. Dann wird dort die Ausgabe an die "Konsole" gesendet. IE9 hatte ein kleines Problem mit console.log()
wenn ich mich erinnere, aber ich möchte nicht zu weit vom Weg abkommen.
HINWEIS: Stellen Sie einfach sicher, dass Sie dieses Zeug nicht im Code belassen, wenn Sie es in die Produktion verschieben. Es ist sehr einfach, diese Zeile einfach auszukommentieren,
//$data['debug'] = $debug;
Und dann werden Ihre Debug-Informationen nicht in der Produktion verfügbar gemacht. Es gibt andere Möglichkeiten, dies automatisch zu tun, aber es hängt davon ab, ob Sie lokal entwickeln und dann auf dem Server veröffentlichen. Sie können es zum Beispiel auf $_SERVER['SERVER_ADDR'];
einschalten das wird ::1
sein oder 127.0.0.1
wenn es lokal ist. Dies hat einige Nachteile, hauptsächlich ist die Serveradresse nicht über die Befehlszeilenschnittstelle (CLI) verfügbar. Daher binde ich es normalerweise in eine globale Konstante ein, die angibt, in welchem "Modus" sich die Site befindet (im gemeinsamen Einstiegspunkt enthalten, normalerweise index.php).
if(!defined('ENV_DEVELOPMENT')) define('ENV_DEVELOPMENT','DEVELOPMENT');
if(!defined('ENV_PRODUCTION')) define('ENV_PRODUCTION','PRODUCTION');
if(!defined('ENVIRONMENT')) define('ENVIRONMENT',ENV_DEVELOPMENT);
//site is in Development mode, uncomment for production
//if(!defined('ENVIRONMENT')) define('ENVIRONMENT',ENV_DEVELOPMENT);
Dann ist es eine einfache Sache, es zu überprüfen:
if(ENVIRONMENT == ENV_PRODUCTION ) $data['debug'] = $debug;
Wenn Sie wissen, wie man Fehlerberichte verwendet, können Sie sogar mit
daran anknüpfen if(ini_get('display_errors') == 1) $data['debug'] = $debug;
Dadurch wird der Debug nur angezeigt, wenn Anzeigefehler aktiviert sind.
Hoffe das hilft.
AKTUALISIEREN
Weil ich es in den Kommentaren erwähnt habe, ist hier ein Beispiel dafür, das in eine Klasse verpackt ist (dies ist eine vereinfachte Version, also habe ich es nicht getestet)
class LibAjax{
public static function respond($callback, $options=0, $depth=32){
$result = ['userdata' => [
'debug' => false,
'error' => false
]];
ob_start();
try{
if(!is_callable($callback)){
//I have better exception in mine, this is just more portable
throw new Exception('Callback is not callable');
}
$callback($result);
}catch(\Exception $e){
//example 'Exception[code:401]'
$result['userdata']['error'] = get_class($e).'[code:'.$e->getCode().']';
//if(ENVIRONMENT == ENV_DEVELOPMENT){
//prevents leaking data in production
$result['userdata']['error'] .= ' '.$e->getMessage();
$result['userdata']['error'] .= PHP_EOL.$e->getTraceAsString();
//}
}
$debug = '';
for($i=0; $i < ob_get_level(); $i++){
//clear any nested output buffers
$debug .= ob_get_clean();
}
//if(ENVIRONMENT == ENV_DEVELPMENT){
//prevents leaking data in production
$result['userdata']['debug'] = $debug;
//}
header('Content-Type: application/json');
echo self::jsonEncode($result, $options, $depth);
}
public static function jsonEncode($result, $options=0, $depth=32){
$json = json_encode($result, $options, $depth);
if(JSON_ERROR_NONE !== json_last_error()){
//debug is not passed in this case, because you cannot be sure that, that was not what caused the error. Such as non-valid UTF-8 in the debug string, depth limit, etc...
$json = json_encode(['userdata' => [
'debug' => false,
'error' => json_last_error_msg()
]],$options);
}
return $json;
}
}
Wenn Sie dann eine AJAX-Antwort machen, wickeln Sie sie einfach so ein (beachten Sie, dass $result als Referenz übergeben wird, auf diese Weise müssen wir nicht zurückgeben, und im Falle einer Ausnahme aktualisieren wir stattdessen $result in "Echtzeit". nach Fertigstellung)
LibAjax::respond( function(&$result){
$result['data'] = 'foo';
});
Wenn Sie zusätzliche Daten in den Abschluss übergeben müssen, vergessen Sie nicht, dass Sie den use
verwenden können Anweisung, wie diese.
$otherdata = 'bar';
LibAjax::respond( function(&$result) use($otherdata){
$result['data'][] = 'foo';
$result['data'][] = $otherdata;
});
Dadurch wird jede Ausgabe abgefangen und in den Debug-Modus versetzt, wenn die Umgebung korrekt (auskommentiert) ist. Bitte stellen Sie sicher, dass Sie eine Art Schutz implementieren, damit die Ausgabe nicht während der Produktion an Clients gesendet wird. Ich kann das nicht genug betonen. Es fängt auch alle Ausnahmen ab, die es in einen Fehler versetzen. Und es behandelt auch den Header und die Kodierung.
Ein großer Vorteil davon ist die konsistente Struktur Ihres JSON, Sie werden (auf der Client-Seite) wissen, dass wenn if(data.userdata.error)
dann haben Sie eine Ausnahme am Backend. Es gibt Ihnen einen Ort, an dem Sie Ihre Header, JSON-Codierung usw. optimieren können...
Eine Anmerkung in PHP7, dass Sie die Throwable-Schnittstelle (anstelle von Exception) hinzufügen müssen oder sollten. Wenn Sie Fehler- und Ausnahmeklassen abfangen möchten, oder zwei Catch-Blöcke ausführen möchten.
Sagen wir einfach, ich mache viel AJAX und hatte es satt, das ständig neu zu schreiben, mein eigentlicher Kurs ist umfangreicher als dieser, aber das ist das Wesentliche.
Prost.
AKTUALISIERUNG1
Dies liegt normalerweise daran, dass Sie nicht den richtigen Header an den Browser zurückgeben. Wenn Sie senden (kurz vor dem Aufruf von json_encode)
header('Content-Type: application/json');
Dadurch weiß der Browser nur, welche Art von Daten er zurückerhält. Eine Sache, die die meisten Leute vergessen, ist, dass im Web alle Antworten in Textform erfolgen. Sogar Bilder oder Dateien herunterladen und Webseiten. Es ist alles nur Text, was diesen Text zu etwas Besonderem macht, ist der Content-Type
dass der Browser denkt, dass es so ist.
Zu header
ist eine Sache zu beachten ist, dass Sie nichts ausgeben können, bevor Sie die Header senden. Dies passt jedoch gut zu dem Code, den ich gepostet habe, da dieser Code die gesamte Ausgabe erfasst und sendet, nachdem der Header gesendet wurde.
Ich habe den ursprünglichen Code aktualisiert, um den Header zu haben, ich hatte ihn in der komplexeren Klasse, die ich später gepostet habe. Aber wenn Sie das hinzufügen, sollte es die Notwendigkeit beseitigen, den JSON manuell zu analysieren.
Eine letzte Sache, die ich erwähnen sollte, ist, zu prüfen, ob ich JSON oder Text zurückerhalten habe. Sie könnten immer noch Text erhalten, falls ein Fehler auftritt, bevor die Ausgabepufferung gestartet wird.
Dafür gibt es zwei Möglichkeiten.
Wenn Daten eine Zeichenfolge sind, die geparst werden muss
$.post(url, {}, function(data){
if( typeof data == 'string'){
try{
data = $.parseJSON(data);
}catch(err){
data = {userdata : {error : data}};
}
}
if(data.userdata){
if( data.userdata.error){
//...etc.
}
}
//....
}
Oder wenn Sie den Header haben und es immer JSON ist, dann ist es etwas einfacher
$.post(url, {}, function(data){
if( typeof data == 'string'){
data = {userdata : {error : data}};
}
if(data.userdata){
if( data.userdata.error){
//...etc.
}
}
//....
}
Hoffe das hilft!
UPDATE2
Da dieses Thema häufig auftaucht, habe ich eine modifizierte Version des obigen Codes auf meinen GitHub gestellt, den Sie hier finden können.
https://github.com/ArtisticPhoenix/MISC/blob/master /AjaxWrapper/AjaxWrapper.php