Wanneer ik te maken heb met AJAX, dat ik teruggeef als JSON, is een truc die ik gebruik om te profiteren van outputbuffering. Je kunt niet zomaar alles herhalen of uitvoeren wat je wilt, omdat het de JSON-gegevens zal verknoeien, dus bijvoorbeeld
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.
Wat dit doet, is alle uitvoer van je script in je JSON-gegevens inpakken, zodat het formaat niet wordt verpest.
Dan kun je aan de javascript-kant console.log
. gebruiken$.post(url, input, function(data){
if(data.debug) console.log(data.debug);
});
Als je niet gewend bent om te debuggen met console.log()
, kunt u meestal op F12
. drukken en open de debugger in de meeste browsers. Dan wordt daar de uitvoer naar de "console" gestuurd. IE9 had een beetje een probleem met console.log()
als ik me goed herinner, maar ik wil niet te ver van de baan gaan.
OPMERKING: Zorg ervoor dat u deze dingen niet in de code achterlaat wanneer u deze naar productie verplaatst, het is heel eenvoudig om deze regel te becommentariëren,
//$data['debug'] = $debug;
En dan zal uw foutopsporingsinformatie niet in productie worden getoond. Er zijn andere manieren om dit automatisch te doen, maar het hangt ervan af of u de ontwikkeling lokaal uitvoert en vervolgens op de server publiceert. U kunt het bijvoorbeeld inschakelen op de $_SERVER['SERVER_ADDR'];
dat wordt ::1
of 127.0.0.1
als het lokaal is. Dit heeft enkele nadelen, voornamelijk het serveradres is niet beschikbaar via de Command Line Interface (CLI). Dus meestal zal ik het koppelen aan een globale constante die zegt in welke "modus" de site zich bevindt (opgenomen in het algemene toegangspunt, meestal 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);
Dan is het eenvoudig om het te controleren:
if(ENVIRONMENT == ENV_PRODUCTION ) $data['debug'] = $debug;
Als u weet hoe u foutrapportage moet gebruiken, kunt u daar zelfs op aansluiten met
if(ini_get('display_errors') == 1) $data['debug'] = $debug;
Die de foutopsporing alleen laat zien als weergavefouten is ingeschakeld.
Ik hoop dat dat helpt.
UPDATE
Omdat ik het in de opmerkingen heb genoemd, is hier een voorbeeld van verpakt in een klas (dit is een vereenvoudigde versie, dus ik heb dit niet getest)
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;
}
}
Wanneer u vervolgens een AJAX-antwoord geeft, wikkelt u het gewoon als volgt in (merk op dat $ resultaat als referentie wordt doorgegeven, op deze manier hoeven we niet terug te keren, en in het geval van een uitzondering werken we $ resultaat bij in "realtime" van bij voltooiing)
LibAjax::respond( function(&$result){
$result['data'] = 'foo';
});
Als u aanvullende gegevens in de afsluiting moet doorgeven, vergeet dan niet dat u de use
. kunt gebruiken verklaring, zoals deze.
$otherdata = 'bar';
LibAjax::respond( function(&$result) use($otherdata){
$result['data'][] = 'foo';
$result['data'][] = $otherdata;
});
Dit zorgt voor het opvangen van alle uitvoer en zet deze in debug, als de omgeving correct is (gecommentarieerd). Zorg er alstublieft voor dat u een soort van bescherming implementeert, zodat de uitvoer niet naar klanten wordt verzonden tijdens productie, ik kan dat niet genoeg benadrukken. Het vangt ook eventuele uitzonderingen op en zet het in de fout. En het behandelt ook de koptekst en codering.
Een groot voordeel hiervan is een consistente structuur voor uw JSON, u weet (aan de clientzijde) dat als if(data.userdata.error)
dan heb je een uitzondering aan de achterkant. Het geeft je één plek om je headers, JSON-codering enz. aan te passen...
Eén opmerking in PHP7 moet of moet de Throwable-interface toevoegen (in plaats van Exception). Als je Error- en Exception-klassen wilt vangen of twee catch-blokken wilt doen.
Laten we zeggen dat ik veel AJAX doe en het zat werd om dit steeds opnieuw te schrijven, mijn eigenlijke les is uitgebreider dan dit, maar dat is de kern ervan.
Proost.
UPDATE1
Dit komt meestal omdat u niet de juiste koptekst doorgeeft aan de browser. Als u verzendt (net voordat u json_encode aanroept)
header('Content-Type: application/json');
Dit laat de browser gewoon weten welk type gegevens het terugkrijgt. Een ding dat de meeste mensen vergeten, is dat op internet alle reacties in tekst worden gedaan. Zelfs afbeeldingen of het downloaden van bestanden en webpagina's. Het is allemaal maar tekst, wat die tekst tot iets speciaals maakt, is het Content-Type
dat de browser denkt dat het is.
Een ding om op te merken over header
is dat u niets kunt uitvoeren voordat u de headers verzendt. Dit past echter goed bij de code die ik heb gepost, omdat die code alle uitvoer zal vastleggen en verzenden nadat de header is verzonden.
Ik heb de originele code bijgewerkt om de koptekst te hebben, ik had het in de meer complexe klasse die ik later heb gepost. Maar als u dat toevoegt, hoeft u de JSON niet meer handmatig te ontleden.
Een laatste ding dat ik moet vermelden dat ik doe, is controleren of ik JSON terug of tekst heb gekregen, je zou nog steeds tekst kunnen krijgen in het geval dat er een fout optreedt voordat de uitvoerbuffering wordt gestart.
Er zijn 2 manieren om dit te doen.
Als Data een tekenreeks is die moet worden geparseerd
$.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.
}
}
//....
}
Of als je de header hebt en het is altijd JSON, dan is het een beetje eenvoudiger
$.post(url, {}, function(data){
if( typeof data == 'string'){
data = {userdata : {error : data}};
}
if(data.userdata){
if( data.userdata.error){
//...etc.
}
}
//....
}
Ik hoop dat dat helpt!
UPDATE2
Omdat dit onderwerp veel voorkomt, heb ik een aangepaste versie van bovenstaande code op mijn GitHub gezet die je hier kunt vinden.
https://github.com/ArtisticPhoenix/MISC/blob/master /AjaxWrapper/AjaxWrapper.php